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/intfloat.h"
31 #include "libavutil/lfg.h"
32 #include "libavutil/md5.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/random_seed.h"
42 #include "rtmpcrypt.h"
50 #define APP_MAX_LENGTH 1024
51 #define PLAYPATH_MAX_LENGTH 512
52 #define TCURL_MAX_LENGTH 1024
53 #define FLASHVER_MAX_LENGTH 64
54 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
55 #define RTMP_HEADER 11
57 /** RTMP protocol handler state */
59 STATE_START, ///< client has not done anything yet
60 STATE_HANDSHAKED, ///< client has performed handshake
61 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
62 STATE_PLAYING, ///< client has started receiving multimedia data from server
63 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
64 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
65 STATE_RECEIVING, ///< received a publish command (for input)
66 STATE_SENDING, ///< received a play command (for output)
67 STATE_STOPPED, ///< the broadcast has been stopped
70 typedef struct TrackedMethod {
75 /** protocol handler context */
76 typedef struct RTMPContext {
78 URLContext* stream; ///< TCP stream used in interactions with RTMP server
79 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
80 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
81 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
82 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
83 int is_input; ///< input/output flag
84 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
85 int live; ///< 0: recorded, -1: live, -2: both
86 char *app; ///< name of application
87 char *conn; ///< append arbitrary AMF data to the Connect message
88 ClientState state; ///< current state
89 int stream_id; ///< ID assigned by the server for the stream
90 uint8_t* flv_data; ///< buffer with data for demuxer
91 int flv_size; ///< current buffer size
92 int flv_off; ///< number of bytes read from current buffer
93 int flv_nb_packets; ///< number of flv packets published
94 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
95 uint32_t receive_report_size; ///< number of bytes after which we should report the number of received bytes to the peer
96 uint64_t bytes_read; ///< number of bytes read from server
97 uint64_t last_bytes_read; ///< number of bytes read last reported to server
98 uint32_t last_timestamp; ///< last timestamp received in a packet
99 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
100 int has_audio; ///< presence of audio data
101 int has_video; ///< presence of video data
102 int received_metadata; ///< Indicates if we have received metadata about the streams
103 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
104 int flv_header_bytes; ///< number of initialized bytes in flv_header
105 int nb_invokes; ///< keeps track of invoke messages
106 char* tcurl; ///< url of the target stream
107 char* flashver; ///< version of the flash plugin
108 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
109 int swfhash_len; ///< length of the SHA256 hash
110 int swfsize; ///< size of the decompressed SWF file
111 char* swfurl; ///< url of the swf player
112 char* swfverify; ///< URL to player swf file, compute hash/size automatically
113 char swfverification[42]; ///< hash of the SWF verification
114 char* pageurl; ///< url of the web page
115 char* subscribe; ///< name of live stream to subscribe
116 int max_sent_unacked; ///< max unacked sent bytes
117 int client_buffer_time; ///< client buffer time in ms
118 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
119 int encrypted; ///< use an encrypted connection (RTMPE only)
120 TrackedMethod*tracked_methods; ///< tracked methods buffer
121 int nb_tracked_methods; ///< number of tracked methods
122 int tracked_methods_size; ///< size of the tracked methods buffer
123 int listen; ///< listen mode flag
124 int listen_timeout; ///< listen timeout to wait for new connections
125 int nb_streamid; ///< The next stream id to return on createStream calls
126 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
129 char auth_params[500];
134 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
135 /** Client key used for digest signing */
136 static const uint8_t rtmp_player_key[] = {
137 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
138 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
140 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
141 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
142 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
145 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
146 /** Key used for RTMP server digest signing */
147 static const uint8_t rtmp_server_key[] = {
148 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
149 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
150 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
152 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
153 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
154 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
157 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
158 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt);
159 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt);
161 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
165 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
166 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
167 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
168 sizeof(*rt->tracked_methods))) < 0) {
169 rt->nb_tracked_methods = 0;
170 rt->tracked_methods_size = 0;
175 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
176 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
177 return AVERROR(ENOMEM);
178 rt->tracked_methods[rt->nb_tracked_methods].id = id;
179 rt->nb_tracked_methods++;
184 static void del_tracked_method(RTMPContext *rt, int index)
186 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
187 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
188 rt->nb_tracked_methods--;
191 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
192 char **tracked_method)
194 RTMPContext *rt = s->priv_data;
200 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
201 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
204 for (i = 0; i < rt->nb_tracked_methods; i++) {
205 if (rt->tracked_methods[i].id != pkt_id)
208 *tracked_method = rt->tracked_methods[i].name;
209 del_tracked_method(rt, i);
216 static void free_tracked_methods(RTMPContext *rt)
220 for (i = 0; i < rt->nb_tracked_methods; i ++)
221 av_freep(&rt->tracked_methods[i].name);
222 av_freep(&rt->tracked_methods);
223 rt->tracked_methods_size = 0;
224 rt->nb_tracked_methods = 0;
227 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
231 if (pkt->type == RTMP_PT_INVOKE && track) {
237 bytestream2_init(&gbc, pkt->data, pkt->size);
238 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
241 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
244 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
248 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
249 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
251 ff_rtmp_packet_destroy(pkt);
255 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
260 /* The type must be B for Boolean, N for number, S for string, O for
261 * object, or Z for null. For Booleans the data must be either 0 or 1 for
262 * FALSE or TRUE, respectively. Likewise for Objects the data must be
263 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
264 * may be named, by prefixing the type with 'N' and specifying the name
265 * before the value (ie. NB:myFlag:1). This option may be used multiple times
266 * to construct arbitrary AMF sequences. */
267 if (param[0] && param[1] == ':') {
270 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
273 value = strchr(field, ':');
279 ff_amf_write_field_name(p, field);
286 ff_amf_write_bool(p, value[0] != '0');
289 ff_amf_write_string(p, value);
292 ff_amf_write_number(p, strtod(value, NULL));
295 ff_amf_write_null(p);
299 ff_amf_write_object_start(p);
301 ff_amf_write_object_end(p);
311 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
312 return AVERROR(EINVAL);
316 * Generate 'connect' call and send it to the server.
318 static int gen_connect(URLContext *s, RTMPContext *rt)
324 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
325 0, 4096 + APP_MAX_LENGTH)) < 0)
330 ff_amf_write_string(&p, "connect");
331 ff_amf_write_number(&p, ++rt->nb_invokes);
332 ff_amf_write_object_start(&p);
333 ff_amf_write_field_name(&p, "app");
334 ff_amf_write_string2(&p, rt->app, rt->auth_params);
337 ff_amf_write_field_name(&p, "type");
338 ff_amf_write_string(&p, "nonprivate");
340 ff_amf_write_field_name(&p, "flashVer");
341 ff_amf_write_string(&p, rt->flashver);
343 if (rt->swfurl || rt->swfverify) {
344 ff_amf_write_field_name(&p, "swfUrl");
346 ff_amf_write_string(&p, rt->swfurl);
348 ff_amf_write_string(&p, rt->swfverify);
351 ff_amf_write_field_name(&p, "tcUrl");
352 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
354 ff_amf_write_field_name(&p, "fpad");
355 ff_amf_write_bool(&p, 0);
356 ff_amf_write_field_name(&p, "capabilities");
357 ff_amf_write_number(&p, 15.0);
359 /* Tell the server we support all the audio codecs except
360 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
361 * which are unused in the RTMP protocol implementation. */
362 ff_amf_write_field_name(&p, "audioCodecs");
363 ff_amf_write_number(&p, 4071.0);
364 ff_amf_write_field_name(&p, "videoCodecs");
365 ff_amf_write_number(&p, 252.0);
366 ff_amf_write_field_name(&p, "videoFunction");
367 ff_amf_write_number(&p, 1.0);
370 ff_amf_write_field_name(&p, "pageUrl");
371 ff_amf_write_string(&p, rt->pageurl);
374 ff_amf_write_object_end(&p);
377 char *param = rt->conn;
379 // Write arbitrary AMF data to the Connect message.
382 param += strspn(param, " ");
385 sep = strchr(param, ' ');
388 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
389 // Invalid AMF parameter.
390 ff_rtmp_packet_destroy(&pkt);
401 pkt.size = p - pkt.data;
403 return rtmp_send_packet(rt, &pkt, 1);
407 #define RTMP_CTRL_ABORT_MESSAGE (2)
409 static int read_connect(URLContext *s, RTMPContext *rt)
411 RTMPPacket pkt = { 0 };
421 // handle RTMP Protocol Control Messages
423 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
424 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
427 ff_rtmp_packet_dump(s, &pkt);
429 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
430 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
431 ff_rtmp_packet_destroy(&pkt);
434 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
435 av_log(s, AV_LOG_ERROR, "received abort message\n");
436 ff_rtmp_packet_destroy(&pkt);
437 return AVERROR_UNKNOWN;
438 } else if (pkt.type == RTMP_PT_BYTES_READ) {
439 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
440 } else if (pkt.type == RTMP_PT_WINDOW_ACK_SIZE) {
441 if ((ret = handle_window_ack_size(s, &pkt)) < 0) {
442 ff_rtmp_packet_destroy(&pkt);
445 } else if (pkt.type == RTMP_PT_SET_PEER_BW) {
446 if ((ret = handle_set_peer_bw(s, &pkt)) < 0) {
447 ff_rtmp_packet_destroy(&pkt);
450 } else if (pkt.type == RTMP_PT_INVOKE) {
451 // received RTMP Command Message
454 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
456 ff_rtmp_packet_destroy(&pkt);
460 bytestream2_init(&gbc, cp, pkt.size);
461 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
462 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
463 ff_rtmp_packet_destroy(&pkt);
464 return AVERROR_INVALIDDATA;
466 if (strcmp(command, "connect")) {
467 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
468 ff_rtmp_packet_destroy(&pkt);
469 return AVERROR_INVALIDDATA;
471 ret = ff_amf_read_number(&gbc, &seqnum);
473 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
474 /* Here one could parse an AMF Object with data as flashVers and others. */
475 ret = ff_amf_get_field_value(gbc.buffer,
476 gbc.buffer + bytestream2_get_bytes_left(&gbc),
477 "app", tmpstr, sizeof(tmpstr));
479 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
480 if (!ret && strcmp(tmpstr, rt->app))
481 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
483 ff_rtmp_packet_destroy(&pkt);
485 // Send Window Acknowledgement Size (as defined in specification)
486 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
487 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
490 // Inform the peer about how often we want acknowledgements about what
491 // we send. (We don't check for the acknowledgements currently.)
492 bytestream_put_be32(&p, rt->max_sent_unacked);
493 pkt.size = p - pkt.data;
494 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
495 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
496 ff_rtmp_packet_destroy(&pkt);
499 // Set Peer Bandwidth
500 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
501 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
504 // Tell the peer to only send this many bytes unless it gets acknowledgements.
505 // This could be any arbitrary value we want here.
506 bytestream_put_be32(&p, rt->max_sent_unacked);
507 bytestream_put_byte(&p, 2); // dynamic
508 pkt.size = p - pkt.data;
509 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
510 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
511 ff_rtmp_packet_destroy(&pkt);
516 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
517 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
521 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
522 bytestream_put_be32(&p, 0); // Stream 0
523 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
524 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
525 ff_rtmp_packet_destroy(&pkt);
530 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
531 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
535 bytestream_put_be32(&p, rt->out_chunk_size);
536 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
537 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
538 ff_rtmp_packet_destroy(&pkt);
542 // Send _result NetConnection.Connect.Success to connect
543 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
545 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
549 ff_amf_write_string(&p, "_result");
550 ff_amf_write_number(&p, seqnum);
552 ff_amf_write_object_start(&p);
553 ff_amf_write_field_name(&p, "fmsVer");
554 ff_amf_write_string(&p, "FMS/3,0,1,123");
555 ff_amf_write_field_name(&p, "capabilities");
556 ff_amf_write_number(&p, 31);
557 ff_amf_write_object_end(&p);
559 ff_amf_write_object_start(&p);
560 ff_amf_write_field_name(&p, "level");
561 ff_amf_write_string(&p, "status");
562 ff_amf_write_field_name(&p, "code");
563 ff_amf_write_string(&p, "NetConnection.Connect.Success");
564 ff_amf_write_field_name(&p, "description");
565 ff_amf_write_string(&p, "Connection succeeded.");
566 ff_amf_write_field_name(&p, "objectEncoding");
567 ff_amf_write_number(&p, 0);
568 ff_amf_write_object_end(&p);
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);
577 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
578 RTMP_PT_INVOKE, 0, 30)) < 0)
581 ff_amf_write_string(&p, "onBWDone");
582 ff_amf_write_number(&p, 0);
583 ff_amf_write_null(&p);
584 ff_amf_write_number(&p, 8192);
585 pkt.size = p - pkt.data;
586 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
587 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
588 ff_rtmp_packet_destroy(&pkt);
594 * Generate 'releaseStream' call and send it to the server. It should make
595 * the server release some channel for media streams.
597 static int gen_release_stream(URLContext *s, RTMPContext *rt)
603 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
604 0, 29 + strlen(rt->playpath))) < 0)
607 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
609 ff_amf_write_string(&p, "releaseStream");
610 ff_amf_write_number(&p, ++rt->nb_invokes);
611 ff_amf_write_null(&p);
612 ff_amf_write_string(&p, rt->playpath);
614 return rtmp_send_packet(rt, &pkt, 1);
618 * Generate 'FCPublish' call and send it to the server. It should make
619 * the server prepare for receiving media streams.
621 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
627 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
628 0, 25 + strlen(rt->playpath))) < 0)
631 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
633 ff_amf_write_string(&p, "FCPublish");
634 ff_amf_write_number(&p, ++rt->nb_invokes);
635 ff_amf_write_null(&p);
636 ff_amf_write_string(&p, rt->playpath);
638 return rtmp_send_packet(rt, &pkt, 1);
642 * Generate 'FCUnpublish' call and send it to the server. It should make
643 * the server destroy stream.
645 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
651 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
652 0, 27 + strlen(rt->playpath))) < 0)
655 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
657 ff_amf_write_string(&p, "FCUnpublish");
658 ff_amf_write_number(&p, ++rt->nb_invokes);
659 ff_amf_write_null(&p);
660 ff_amf_write_string(&p, rt->playpath);
662 return rtmp_send_packet(rt, &pkt, 0);
666 * Generate 'createStream' call and send it to the server. It should make
667 * the server allocate some channel for media streams.
669 static int gen_create_stream(URLContext *s, RTMPContext *rt)
675 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
677 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
682 ff_amf_write_string(&p, "createStream");
683 ff_amf_write_number(&p, ++rt->nb_invokes);
684 ff_amf_write_null(&p);
686 return rtmp_send_packet(rt, &pkt, 1);
691 * Generate 'deleteStream' call and send it to the server. It should make
692 * the server remove some channel for media streams.
694 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
700 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
702 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
707 ff_amf_write_string(&p, "deleteStream");
708 ff_amf_write_number(&p, ++rt->nb_invokes);
709 ff_amf_write_null(&p);
710 ff_amf_write_number(&p, rt->stream_id);
712 return rtmp_send_packet(rt, &pkt, 0);
716 * Generate 'getStreamLength' call and send it to the server. If the server
717 * knows the duration of the selected stream, it will reply with the duration
720 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
726 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
727 0, 31 + strlen(rt->playpath))) < 0)
731 ff_amf_write_string(&p, "getStreamLength");
732 ff_amf_write_number(&p, ++rt->nb_invokes);
733 ff_amf_write_null(&p);
734 ff_amf_write_string(&p, rt->playpath);
736 return rtmp_send_packet(rt, &pkt, 1);
740 * Generate client buffer time and send it to the server.
742 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
748 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
753 bytestream_put_be16(&p, 3); // SetBuffer Length
754 bytestream_put_be32(&p, rt->stream_id);
755 bytestream_put_be32(&p, rt->client_buffer_time);
757 return rtmp_send_packet(rt, &pkt, 0);
761 * Generate 'play' call and send it to the server, then ping the server
762 * to start actual playing.
764 static int gen_play(URLContext *s, RTMPContext *rt)
770 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
772 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
773 0, 29 + strlen(rt->playpath))) < 0)
776 pkt.extra = rt->stream_id;
779 ff_amf_write_string(&p, "play");
780 ff_amf_write_number(&p, ++rt->nb_invokes);
781 ff_amf_write_null(&p);
782 ff_amf_write_string(&p, rt->playpath);
783 ff_amf_write_number(&p, rt->live * 1000);
785 return rtmp_send_packet(rt, &pkt, 1);
788 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
794 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
797 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
800 pkt.extra = rt->stream_id;
803 ff_amf_write_string(&p, "seek");
804 ff_amf_write_number(&p, 0); //no tracking back responses
805 ff_amf_write_null(&p); //as usual, the first null param
806 ff_amf_write_number(&p, timestamp); //where we want to jump
808 return rtmp_send_packet(rt, &pkt, 1);
812 * Generate a pause packet that either pauses or unpauses the current stream.
814 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
820 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
823 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
826 pkt.extra = rt->stream_id;
829 ff_amf_write_string(&p, "pause");
830 ff_amf_write_number(&p, 0); //no tracking back responses
831 ff_amf_write_null(&p); //as usual, the first null param
832 ff_amf_write_bool(&p, pause); // pause or unpause
833 ff_amf_write_number(&p, timestamp); //where we pause the stream
835 return rtmp_send_packet(rt, &pkt, 1);
839 * Generate 'publish' call and send it to the server.
841 static int gen_publish(URLContext *s, RTMPContext *rt)
847 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
849 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
850 0, 30 + strlen(rt->playpath))) < 0)
853 pkt.extra = rt->stream_id;
856 ff_amf_write_string(&p, "publish");
857 ff_amf_write_number(&p, ++rt->nb_invokes);
858 ff_amf_write_null(&p);
859 ff_amf_write_string(&p, rt->playpath);
860 ff_amf_write_string(&p, "live");
862 return rtmp_send_packet(rt, &pkt, 1);
866 * Generate ping reply and send it to the server.
868 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
874 if (ppkt->size < 6) {
875 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
877 return AVERROR_INVALIDDATA;
880 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
881 ppkt->timestamp + 1, 6)) < 0)
885 bytestream_put_be16(&p, 7); // PingResponse
886 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
888 return rtmp_send_packet(rt, &pkt, 0);
892 * Generate SWF verification message and send it to the server.
894 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
900 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
901 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
906 bytestream_put_be16(&p, 27);
907 memcpy(p, rt->swfverification, 42);
909 return rtmp_send_packet(rt, &pkt, 0);
913 * Generate window acknowledgement size message and send it to the server.
915 static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
921 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
926 bytestream_put_be32(&p, rt->max_sent_unacked);
928 return rtmp_send_packet(rt, &pkt, 0);
932 * Generate check bandwidth message and send it to the server.
934 static int gen_check_bw(URLContext *s, RTMPContext *rt)
940 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
945 ff_amf_write_string(&p, "_checkbw");
946 ff_amf_write_number(&p, ++rt->nb_invokes);
947 ff_amf_write_null(&p);
949 return rtmp_send_packet(rt, &pkt, 1);
953 * Generate report on bytes read so far and send it to the server.
955 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
961 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
966 bytestream_put_be32(&p, rt->bytes_read);
968 return rtmp_send_packet(rt, &pkt, 0);
971 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
972 const char *subscribe)
978 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
979 0, 27 + strlen(subscribe))) < 0)
983 ff_amf_write_string(&p, "FCSubscribe");
984 ff_amf_write_number(&p, ++rt->nb_invokes);
985 ff_amf_write_null(&p);
986 ff_amf_write_string(&p, subscribe);
988 return rtmp_send_packet(rt, &pkt, 1);
992 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
993 * will be stored) into that packet.
995 * @param buf handshake data (1536 bytes)
996 * @param encrypted use an encrypted connection (RTMPE)
997 * @return offset to the digest inside input data
999 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1001 int ret, digest_pos;
1004 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1006 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1008 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1009 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1018 * Verify that the received server response has the expected digest value.
1020 * @param buf handshake data received from the server (1536 bytes)
1021 * @param off position to search digest offset from
1022 * @return 0 if digest is valid, digest position otherwise
1024 static int rtmp_validate_digest(uint8_t *buf, int off)
1027 int ret, digest_pos;
1029 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1031 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1032 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1037 if (!memcmp(digest, buf + digest_pos, 32))
1042 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1048 if (rt->swfhash_len != 32) {
1049 av_log(s, AV_LOG_ERROR,
1050 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1051 return AVERROR(EINVAL);
1054 p = &rt->swfverification[0];
1055 bytestream_put_byte(&p, 1);
1056 bytestream_put_byte(&p, 1);
1057 bytestream_put_be32(&p, rt->swfsize);
1058 bytestream_put_be32(&p, rt->swfsize);
1060 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1067 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1068 uint8_t **out_data, int64_t *out_size)
1070 z_stream zs = { 0 };
1075 zs.avail_in = in_size;
1076 zs.next_in = in_data;
1077 ret = inflateInit(&zs);
1079 return AVERROR_UNKNOWN;
1082 uint8_t tmp_buf[16384];
1084 zs.avail_out = sizeof(tmp_buf);
1085 zs.next_out = tmp_buf;
1087 ret = inflate(&zs, Z_NO_FLUSH);
1088 if (ret != Z_OK && ret != Z_STREAM_END) {
1089 ret = AVERROR_UNKNOWN;
1093 size = sizeof(tmp_buf) - zs.avail_out;
1094 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1095 ret = AVERROR(ENOMEM);
1100 memcpy(*out_data + *out_size, tmp_buf, size);
1102 } while (zs.avail_out == 0);
1110 static int rtmp_calc_swfhash(URLContext *s)
1112 RTMPContext *rt = s->priv_data;
1113 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1120 /* Get the SWF player file. */
1121 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1122 &s->interrupt_callback, NULL,
1123 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1124 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1128 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1133 if (!(in_data = av_malloc(in_size))) {
1134 ret = AVERROR(ENOMEM);
1138 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1142 ret = AVERROR_INVALIDDATA;
1146 if (!memcmp(in_data, "CWS", 3)) {
1149 /* Decompress the SWF player file using Zlib. */
1150 if (!(out_data = av_malloc(8))) {
1151 ret = AVERROR(ENOMEM);
1154 *in_data = 'F'; // magic stuff
1155 memcpy(out_data, in_data, 8);
1158 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1159 &out_data, &out_size)) < 0)
1164 av_log(s, AV_LOG_ERROR,
1165 "Zlib is required for decompressing the SWF player file.\n");
1166 ret = AVERROR(EINVAL);
1174 /* Compute the SHA256 hash of the SWF player file. */
1175 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1176 "Genuine Adobe Flash Player 001", 30,
1180 /* Set SWFVerification parameters. */
1181 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1182 rt->swfsize = swfsize;
1186 av_freep(&out_data);
1187 ffurl_close(stream);
1192 * Perform handshake with the server by means of exchanging pseudorandom data
1193 * signed with HMAC-SHA2 digest.
1195 * @return 0 if handshake succeeds, negative value otherwise
1197 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1200 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1201 3, // unencrypted data
1202 0, 0, 0, 0, // client uptime
1208 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1209 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1211 int server_pos, client_pos;
1212 uint8_t digest[32], signature[32];
1215 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1217 av_lfg_init(&rnd, 0xDEADC0DE);
1218 // generate handshake packet - 1536 bytes of pseudorandom data
1219 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1220 tosend[i] = av_lfg_get(&rnd) >> 24;
1222 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1223 /* When the client wants to use RTMPE, we have to change the command
1224 * byte to 0x06 which means to use encrypted data and we have to set
1225 * the flash version to at least 9.0.115.0. */
1232 /* Initialize the Diffie-Hellmann context and generate the public key
1233 * to send to the server. */
1234 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1238 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1242 if ((ret = ffurl_write(rt->stream, tosend,
1243 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1244 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1248 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1249 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1250 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1254 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1255 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1256 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1260 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1261 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1262 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1264 if (rt->is_input && serverdata[5] >= 3) {
1265 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1271 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1276 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1277 return AVERROR(EIO);
1281 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1282 * key are the last 32 bytes of the server handshake. */
1284 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1285 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1289 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1290 rtmp_server_key, sizeof(rtmp_server_key),
1295 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1296 0, digest, 32, signature);
1300 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1301 /* Compute the shared secret key sent by the server and initialize
1302 * the RC4 encryption. */
1303 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1304 tosend + 1, type)) < 0)
1307 /* Encrypt the signature received by the server. */
1308 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1311 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1312 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1313 return AVERROR(EIO);
1316 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1317 tosend[i] = av_lfg_get(&rnd) >> 24;
1318 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1319 rtmp_player_key, sizeof(rtmp_player_key),
1324 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1326 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1330 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1331 /* Encrypt the signature to be send to the server. */
1332 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1333 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1337 // write reply back to the server
1338 if ((ret = ffurl_write(rt->stream, tosend,
1339 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1342 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1343 /* Set RC4 keys for encryption and update the keystreams. */
1344 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1348 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1349 /* Compute the shared secret key sent by the server and initialize
1350 * the RC4 encryption. */
1351 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1352 tosend + 1, 1)) < 0)
1355 if (serverdata[0] == 9) {
1356 /* Encrypt the signature received by the server. */
1357 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1362 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1363 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1366 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1367 /* Set RC4 keys for encryption and update the keystreams. */
1368 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1376 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1377 uint32_t *second_int, char *arraydata,
1382 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1383 RTMP_HANDSHAKE_PACKET_SIZE);
1385 return AVERROR(EIO);
1386 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1387 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1388 " not following standard\n", (int)inoutsize);
1389 return AVERROR(EINVAL);
1392 *first_int = AV_RB32(arraydata);
1393 *second_int = AV_RB32(arraydata + 4);
1397 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1398 uint32_t second_int, char *arraydata, int size)
1402 AV_WB32(arraydata, first_int);
1403 AV_WB32(arraydata + 4, second_int);
1404 inoutsize = ffurl_write(rt->stream, arraydata,
1405 RTMP_HANDSHAKE_PACKET_SIZE);
1406 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1407 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1408 return AVERROR(EIO);
1415 * rtmp handshake server side
1417 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1419 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1421 uint32_t hs_my_epoch;
1422 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1423 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1430 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1431 if (inoutsize <= 0) {
1432 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1433 return AVERROR(EIO);
1436 if (buffer[0] != 3) {
1437 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1438 return AVERROR(EIO);
1440 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1441 av_log(s, AV_LOG_ERROR,
1442 "Unable to write answer - RTMP S0\n");
1443 return AVERROR(EIO);
1446 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1447 RTMP_HANDSHAKE_PACKET_SIZE);
1449 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1453 /* By now same epoch will be sent */
1454 hs_my_epoch = hs_epoch;
1455 /* Generate random */
1456 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1458 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1460 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1461 RTMP_HANDSHAKE_PACKET_SIZE);
1463 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1467 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1468 RTMP_HANDSHAKE_PACKET_SIZE);
1470 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1474 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1475 RTMP_HANDSHAKE_PACKET_SIZE);
1477 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1480 if (temp != hs_my_epoch)
1481 av_log(s, AV_LOG_WARNING,
1482 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1483 if (memcmp(buffer + 8, hs_s1 + 8,
1484 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1485 av_log(s, AV_LOG_WARNING,
1486 "Erroneous C2 Message random does not match up\n");
1491 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1493 RTMPContext *rt = s->priv_data;
1496 if (pkt->size < 4) {
1497 av_log(s, AV_LOG_ERROR,
1498 "Too short chunk size change packet (%d)\n",
1500 return AVERROR_INVALIDDATA;
1503 if (!rt->is_input) {
1504 /* Send the same chunk size change packet back to the server,
1505 * setting the outgoing chunk size to the same as the incoming one. */
1506 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1507 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1509 rt->out_chunk_size = AV_RB32(pkt->data);
1512 rt->in_chunk_size = AV_RB32(pkt->data);
1513 if (rt->in_chunk_size <= 0) {
1514 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1516 return AVERROR_INVALIDDATA;
1518 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1524 static int handle_user_control(URLContext *s, RTMPPacket *pkt)
1526 RTMPContext *rt = s->priv_data;
1529 if (pkt->size < 2) {
1530 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1532 return AVERROR_INVALIDDATA;
1535 t = AV_RB16(pkt->data);
1536 if (t == 6) { // PingRequest
1537 if ((ret = gen_pong(s, rt, pkt)) < 0)
1539 } else if (t == 26) {
1541 if ((ret = gen_swf_verification(s, rt)) < 0)
1544 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1551 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
1553 RTMPContext *rt = s->priv_data;
1555 if (pkt->size < 4) {
1556 av_log(s, AV_LOG_ERROR,
1557 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1559 return AVERROR_INVALIDDATA;
1562 // We currently don't check how much the peer has acknowledged of
1563 // what we have sent. To do that properly, we should call
1564 // gen_window_ack_size here, to tell the peer that we want an
1565 // acknowledgement with (at least) that interval.
1566 rt->max_sent_unacked = AV_RB32(pkt->data);
1567 if (rt->max_sent_unacked <= 0) {
1568 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1569 rt->max_sent_unacked);
1570 return AVERROR_INVALIDDATA;
1573 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1578 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
1580 RTMPContext *rt = s->priv_data;
1582 if (pkt->size < 4) {
1583 av_log(s, AV_LOG_ERROR,
1584 "Too short window acknowledgement size packet (%d)\n",
1586 return AVERROR_INVALIDDATA;
1589 rt->receive_report_size = AV_RB32(pkt->data);
1590 if (rt->receive_report_size <= 0) {
1591 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1592 rt->receive_report_size);
1593 return AVERROR_INVALIDDATA;
1595 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1596 // Send an Acknowledgement packet after receiving half the maximum
1597 // size, to make sure the peer can keep on sending without waiting
1598 // for acknowledgements.
1599 rt->receive_report_size >>= 1;
1604 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1605 const char *opaque, const char *challenge)
1608 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1609 struct AVMD5 *md5 = av_md5_alloc();
1611 return AVERROR(ENOMEM);
1613 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1616 av_md5_update(md5, user, strlen(user));
1617 av_md5_update(md5, salt, strlen(salt));
1618 av_md5_update(md5, rt->password, strlen(rt->password));
1619 av_md5_final(md5, hash);
1620 av_base64_encode(hashstr, sizeof(hashstr), hash,
1623 av_md5_update(md5, hashstr, strlen(hashstr));
1625 av_md5_update(md5, opaque, strlen(opaque));
1627 av_md5_update(md5, challenge, strlen(challenge));
1628 av_md5_update(md5, challenge2, strlen(challenge2));
1629 av_md5_final(md5, hash);
1630 av_base64_encode(hashstr, sizeof(hashstr), hash,
1632 snprintf(rt->auth_params, sizeof(rt->auth_params),
1633 "?authmod=%s&user=%s&challenge=%s&response=%s",
1634 "adobe", user, challenge2, hashstr);
1636 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1637 "&opaque=%s", opaque);
1643 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1646 char hashstr1[33], hashstr2[33];
1647 const char *realm = "live";
1648 const char *method = "publish";
1649 const char *qop = "auth";
1650 const char *nc = "00000001";
1652 struct AVMD5 *md5 = av_md5_alloc();
1654 return AVERROR(ENOMEM);
1656 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1659 av_md5_update(md5, user, strlen(user));
1660 av_md5_update(md5, ":", 1);
1661 av_md5_update(md5, realm, strlen(realm));
1662 av_md5_update(md5, ":", 1);
1663 av_md5_update(md5, rt->password, strlen(rt->password));
1664 av_md5_final(md5, hash);
1665 ff_data_to_hex(hashstr1, hash, 16, 1);
1666 hashstr1[32] = '\0';
1669 av_md5_update(md5, method, strlen(method));
1670 av_md5_update(md5, ":/", 2);
1671 av_md5_update(md5, rt->app, strlen(rt->app));
1672 if (!strchr(rt->app, '/'))
1673 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1674 av_md5_final(md5, hash);
1675 ff_data_to_hex(hashstr2, hash, 16, 1);
1676 hashstr2[32] = '\0';
1679 av_md5_update(md5, hashstr1, strlen(hashstr1));
1680 av_md5_update(md5, ":", 1);
1682 av_md5_update(md5, nonce, strlen(nonce));
1683 av_md5_update(md5, ":", 1);
1684 av_md5_update(md5, nc, strlen(nc));
1685 av_md5_update(md5, ":", 1);
1686 av_md5_update(md5, cnonce, strlen(cnonce));
1687 av_md5_update(md5, ":", 1);
1688 av_md5_update(md5, qop, strlen(qop));
1689 av_md5_update(md5, ":", 1);
1690 av_md5_update(md5, hashstr2, strlen(hashstr2));
1691 av_md5_final(md5, hash);
1692 ff_data_to_hex(hashstr1, hash, 16, 1);
1694 snprintf(rt->auth_params, sizeof(rt->auth_params),
1695 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1696 "llnw", user, nonce, cnonce, nc, hashstr1);
1702 static int handle_connect_error(URLContext *s, const char *desc)
1704 RTMPContext *rt = s->priv_data;
1705 char buf[300], *ptr, authmod[15];
1707 const char *user = "", *salt = "", *opaque = NULL,
1708 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1710 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1711 !(cptr = strstr(desc, "authmod=llnw"))) {
1712 av_log(s, AV_LOG_ERROR,
1713 "Unknown connect error (unsupported authentication method?)\n");
1714 return AVERROR_UNKNOWN;
1716 cptr += strlen("authmod=");
1717 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1718 authmod[i++] = *cptr++;
1721 if (!rt->username[0] || !rt->password[0]) {
1722 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1723 return AVERROR_UNKNOWN;
1726 if (strstr(desc, "?reason=authfailed")) {
1727 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1728 return AVERROR_UNKNOWN;
1729 } else if (strstr(desc, "?reason=nosuchuser")) {
1730 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1731 return AVERROR_UNKNOWN;
1734 if (rt->auth_tried) {
1735 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1736 return AVERROR_UNKNOWN;
1739 rt->auth_params[0] = '\0';
1741 if (strstr(desc, "code=403 need auth")) {
1742 snprintf(rt->auth_params, sizeof(rt->auth_params),
1743 "?authmod=%s&user=%s", authmod, rt->username);
1747 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1748 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1749 return AVERROR_UNKNOWN;
1752 av_strlcpy(buf, cptr + 1, sizeof(buf));
1756 char *next = strchr(ptr, '&');
1757 char *value = strchr(ptr, '=');
1762 if (!strcmp(ptr, "user")) {
1764 } else if (!strcmp(ptr, "salt")) {
1766 } else if (!strcmp(ptr, "opaque")) {
1768 } else if (!strcmp(ptr, "challenge")) {
1770 } else if (!strcmp(ptr, "nonce")) {
1773 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1776 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1781 if (!strcmp(authmod, "adobe")) {
1782 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1785 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1793 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1795 RTMPContext *rt = s->priv_data;
1796 const uint8_t *data_end = pkt->data + pkt->size;
1797 char *tracked_method = NULL;
1798 int level = AV_LOG_ERROR;
1799 uint8_t tmpstr[256];
1802 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1805 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1806 "description", tmpstr, sizeof(tmpstr))) {
1807 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1808 !strcmp(tracked_method, "releaseStream") ||
1809 !strcmp(tracked_method, "FCSubscribe") ||
1810 !strcmp(tracked_method, "FCPublish"))) {
1811 /* Gracefully ignore Adobe-specific historical artifact errors. */
1812 level = AV_LOG_WARNING;
1814 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1815 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1817 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1818 ret = handle_connect_error(s, tmpstr);
1820 rt->do_reconnect = 1;
1821 level = AV_LOG_VERBOSE;
1824 ret = AVERROR_UNKNOWN;
1825 av_log(s, level, "Server error: %s\n", tmpstr);
1828 av_free(tracked_method);
1832 static int write_begin(URLContext *s)
1834 RTMPContext *rt = s->priv_data;
1836 RTMPPacket spkt = { 0 };
1839 // Send Stream Begin 1
1840 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1841 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1842 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1846 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1847 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1848 bytestream2_put_be32(&pbc, rt->nb_streamid);
1850 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1851 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1853 ff_rtmp_packet_destroy(&spkt);
1858 static int write_status(URLContext *s, RTMPPacket *pkt,
1859 const char *status, const char *filename)
1861 RTMPContext *rt = s->priv_data;
1862 RTMPPacket spkt = { 0 };
1863 char statusmsg[128];
1867 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1869 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1870 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1875 spkt.extra = pkt->extra;
1876 ff_amf_write_string(&pp, "onStatus");
1877 ff_amf_write_number(&pp, 0);
1878 ff_amf_write_null(&pp);
1880 ff_amf_write_object_start(&pp);
1881 ff_amf_write_field_name(&pp, "level");
1882 ff_amf_write_string(&pp, "status");
1883 ff_amf_write_field_name(&pp, "code");
1884 ff_amf_write_string(&pp, status);
1885 ff_amf_write_field_name(&pp, "description");
1886 snprintf(statusmsg, sizeof(statusmsg),
1887 "%s is now published", filename);
1888 ff_amf_write_string(&pp, statusmsg);
1889 ff_amf_write_field_name(&pp, "details");
1890 ff_amf_write_string(&pp, filename);
1891 ff_amf_write_object_end(&pp);
1893 spkt.size = pp - spkt.data;
1894 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1895 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1896 ff_rtmp_packet_destroy(&spkt);
1901 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1903 RTMPContext *rt = s->priv_data;
1909 const uint8_t *p = pkt->data;
1911 RTMPPacket spkt = { 0 };
1915 bytestream2_init(&gbc, p, pkt->size);
1916 if (ff_amf_read_string(&gbc, command, sizeof(command),
1918 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1919 return AVERROR_INVALIDDATA;
1922 ret = ff_amf_read_number(&gbc, &seqnum);
1925 ret = ff_amf_read_null(&gbc);
1928 if (!strcmp(command, "FCPublish") ||
1929 !strcmp(command, "publish")) {
1930 ret = ff_amf_read_string(&gbc, filename,
1931 sizeof(filename), &stringlen);
1933 if (ret == AVERROR(EINVAL))
1934 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1936 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1941 pchar = strrchr(s->filename, '/');
1943 av_log(s, AV_LOG_WARNING,
1944 "Unable to find / in url %s, bad format\n",
1946 pchar = s->filename;
1949 if (strcmp(pchar, filename))
1950 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1951 " %s\n", filename, pchar);
1953 rt->state = STATE_RECEIVING;
1956 if (!strcmp(command, "FCPublish")) {
1957 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1959 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1960 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1964 ff_amf_write_string(&pp, "onFCPublish");
1965 } else if (!strcmp(command, "publish")) {
1966 ret = write_begin(s);
1970 // Send onStatus(NetStream.Publish.Start)
1971 return write_status(s, pkt, "NetStream.Publish.Start",
1973 } else if (!strcmp(command, "play")) {
1974 ret = write_begin(s);
1977 rt->state = STATE_SENDING;
1978 return write_status(s, pkt, "NetStream.Play.Start",
1981 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1983 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1984 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1988 ff_amf_write_string(&pp, "_result");
1989 ff_amf_write_number(&pp, seqnum);
1990 ff_amf_write_null(&pp);
1991 if (!strcmp(command, "createStream")) {
1993 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1994 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1995 ff_amf_write_number(&pp, rt->nb_streamid);
1996 /* By now we don't control which streams are removed in
1997 * deleteStream. There is no stream creation control
1998 * if a client creates more than 2^32 - 2 streams. */
2001 spkt.size = pp - spkt.data;
2002 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2003 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2004 ff_rtmp_packet_destroy(&spkt);
2009 * Read the AMF_NUMBER response ("_result") to a function call
2010 * (e.g. createStream()). This response should be made up of the AMF_STRING
2011 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2012 * successful response, we will return set the value to number (otherwise number
2013 * will not be changed).
2015 * @return 0 if reading the value succeeds, negative value otherwise
2017 static int read_number_result(RTMPPacket *pkt, double *number)
2019 // We only need to fit "_result" in this.
2020 uint8_t strbuffer[8];
2025 bytestream2_init(&gbc, pkt->data, pkt->size);
2027 // Value 1/4: "_result" as AMF_STRING
2028 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2029 return AVERROR_INVALIDDATA;
2030 if (strcmp(strbuffer, "_result"))
2031 return AVERROR_INVALIDDATA;
2032 // Value 2/4: The callee reference number
2033 if (ff_amf_read_number(&gbc, &numbuffer))
2034 return AVERROR_INVALIDDATA;
2036 if (ff_amf_read_null(&gbc))
2037 return AVERROR_INVALIDDATA;
2038 // Value 4/4: The response as AMF_NUMBER
2039 if (ff_amf_read_number(&gbc, &numbuffer))
2040 return AVERROR_INVALIDDATA;
2042 *number = numbuffer;
2047 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2049 RTMPContext *rt = s->priv_data;
2050 char *tracked_method = NULL;
2053 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2056 if (!tracked_method) {
2057 /* Ignore this reply when the current method is not tracked. */
2061 if (!strcmp(tracked_method, "connect")) {
2062 if (!rt->is_input) {
2063 if ((ret = gen_release_stream(s, rt)) < 0)
2066 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2069 if ((ret = gen_window_ack_size(s, rt)) < 0)
2073 if ((ret = gen_create_stream(s, rt)) < 0)
2077 /* Send the FCSubscribe command when the name of live
2078 * stream is defined by the user or if it's a live stream. */
2079 if (rt->subscribe) {
2080 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2082 } else if (rt->live == -1) {
2083 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2087 } else if (!strcmp(tracked_method, "createStream")) {
2089 if (read_number_result(pkt, &stream_id)) {
2090 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2092 rt->stream_id = stream_id;
2095 if (!rt->is_input) {
2096 if ((ret = gen_publish(s, rt)) < 0)
2099 if (rt->live != -1) {
2100 if ((ret = gen_get_stream_length(s, rt)) < 0)
2103 if ((ret = gen_play(s, rt)) < 0)
2105 if ((ret = gen_buffer_time(s, rt)) < 0)
2108 } else if (!strcmp(tracked_method, "getStreamLength")) {
2109 if (read_number_result(pkt, &rt->duration)) {
2110 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2115 av_free(tracked_method);
2119 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2121 RTMPContext *rt = s->priv_data;
2122 const uint8_t *data_end = pkt->data + pkt->size;
2123 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2124 uint8_t tmpstr[256];
2127 for (i = 0; i < 2; i++) {
2128 t = ff_amf_tag_size(ptr, data_end);
2134 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2135 if (!t && !strcmp(tmpstr, "error")) {
2136 t = ff_amf_get_field_value(ptr, data_end,
2137 "description", tmpstr, sizeof(tmpstr));
2138 if (t || !tmpstr[0])
2139 t = ff_amf_get_field_value(ptr, data_end, "code",
2140 tmpstr, sizeof(tmpstr));
2142 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2146 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2147 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2148 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2149 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2150 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2151 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2156 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2158 RTMPContext *rt = s->priv_data;
2161 //TODO: check for the messages sent for wrong state?
2162 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2163 if ((ret = handle_invoke_error(s, pkt)) < 0)
2165 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2166 if ((ret = handle_invoke_result(s, pkt)) < 0)
2168 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2169 if ((ret = handle_invoke_status(s, pkt)) < 0)
2171 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2172 if ((ret = gen_check_bw(s, rt)) < 0)
2174 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2175 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2176 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2177 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2178 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2179 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2180 if ((ret = send_invoke_response(s, pkt)) < 0)
2187 static int update_offset(RTMPContext *rt, int size)
2191 // generate packet header and put data into buffer for FLV demuxer
2192 if (rt->flv_off < rt->flv_size) {
2193 // There is old unread data in the buffer, thus append at the end
2194 old_flv_size = rt->flv_size;
2195 rt->flv_size += size;
2197 // All data has been read, write the new data at the start of the buffer
2199 rt->flv_size = size;
2203 return old_flv_size;
2206 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2208 int old_flv_size, ret;
2210 const uint8_t *data = pkt->data + skip;
2211 const int size = pkt->size - skip;
2212 uint32_t ts = pkt->timestamp;
2214 if (pkt->type == RTMP_PT_AUDIO) {
2216 } else if (pkt->type == RTMP_PT_VIDEO) {
2220 old_flv_size = update_offset(rt, size + 15);
2222 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2223 rt->flv_size = rt->flv_off = 0;
2226 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2227 bytestream2_skip_p(&pbc, old_flv_size);
2228 bytestream2_put_byte(&pbc, pkt->type);
2229 bytestream2_put_be24(&pbc, size);
2230 bytestream2_put_be24(&pbc, ts);
2231 bytestream2_put_byte(&pbc, ts >> 24);
2232 bytestream2_put_be24(&pbc, 0);
2233 bytestream2_put_buffer(&pbc, data, size);
2234 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2239 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2241 RTMPContext *rt = s->priv_data;
2242 uint8_t commandbuffer[64];
2243 char statusmsg[128];
2244 int stringlen, ret, skip = 0;
2247 bytestream2_init(&gbc, pkt->data, pkt->size);
2248 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2250 return AVERROR_INVALIDDATA;
2252 if (!strcmp(commandbuffer, "onMetaData")) {
2253 // metadata properties should be stored in a mixed array
2254 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2255 // We have found a metaData Array so flv can determine the streams
2257 rt->received_metadata = 1;
2258 // skip 32-bit max array index
2259 bytestream2_skip(&gbc, 4);
2260 while (bytestream2_get_bytes_left(&gbc) > 3) {
2261 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2263 return AVERROR_INVALIDDATA;
2264 // We do not care about the content of the property (yet).
2265 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2267 return AVERROR_INVALIDDATA;
2268 bytestream2_skip(&gbc, stringlen);
2270 // The presence of the following properties indicates that the
2271 // respective streams are present.
2272 if (!strcmp(statusmsg, "videocodecid")) {
2275 if (!strcmp(statusmsg, "audiocodecid")) {
2279 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2280 return AVERROR_INVALIDDATA;
2284 // Skip the @setDataFrame string and validate it is a notification
2285 if (!strcmp(commandbuffer, "@setDataFrame")) {
2286 skip = gbc.buffer - pkt->data;
2287 ret = ff_amf_read_string(&gbc, statusmsg,
2288 sizeof(statusmsg), &stringlen);
2290 return AVERROR_INVALIDDATA;
2293 return append_flv_data(rt, pkt, skip);
2297 * Parse received packet and possibly perform some action depending on
2298 * the packet contents.
2299 * @return 0 for no errors, negative values for serious errors which prevent
2300 * further communications, positive values for uncritical errors
2302 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2307 ff_rtmp_packet_dump(s, pkt);
2310 switch (pkt->type) {
2311 case RTMP_PT_BYTES_READ:
2312 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2314 case RTMP_PT_CHUNK_SIZE:
2315 if ((ret = handle_chunk_size(s, pkt)) < 0)
2318 case RTMP_PT_USER_CONTROL:
2319 if ((ret = handle_user_control(s, pkt)) < 0)
2322 case RTMP_PT_SET_PEER_BW:
2323 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2326 case RTMP_PT_WINDOW_ACK_SIZE:
2327 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2330 case RTMP_PT_INVOKE:
2331 if ((ret = handle_invoke(s, pkt)) < 0)
2336 case RTMP_PT_METADATA:
2337 case RTMP_PT_NOTIFY:
2338 /* Audio, Video and Metadata packets are parsed in get_packet() */
2341 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2347 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2349 int ret, old_flv_size, type;
2350 const uint8_t *next;
2353 uint32_t ts, cts, pts = 0;
2355 old_flv_size = update_offset(rt, pkt->size);
2357 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2358 rt->flv_size = rt->flv_off = 0;
2363 p = rt->flv_data + old_flv_size;
2365 /* copy data while rewriting timestamps */
2366 ts = pkt->timestamp;
2368 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2369 type = bytestream_get_byte(&next);
2370 size = bytestream_get_be24(&next);
2371 cts = bytestream_get_be24(&next);
2372 cts |= bytestream_get_byte(&next) << 24;
2377 if (size + 3 + 4 > pkt->data + pkt->size - next)
2379 bytestream_put_byte(&p, type);
2380 bytestream_put_be24(&p, size);
2381 bytestream_put_be24(&p, ts);
2382 bytestream_put_byte(&p, ts >> 24);
2383 memcpy(p, next, size + 3 + 4);
2385 bytestream_put_be32(&p, size + RTMP_HEADER);
2386 next += size + 3 + 4;
2388 if (p != rt->flv_data + rt->flv_size) {
2389 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2390 "RTMP_PT_METADATA packet\n");
2391 rt->flv_size = p - rt->flv_data;
2398 * Interact with the server by receiving and sending RTMP packets until
2399 * there is some significant data (media data or expected status notification).
2401 * @param s reading context
2402 * @param for_header non-zero value tells function to work until it
2403 * gets notification from the server that playing has been started,
2404 * otherwise function will work until some media data is received (or
2406 * @return 0 for successful operation, negative value in case of error
2408 static int get_packet(URLContext *s, int for_header)
2410 RTMPContext *rt = s->priv_data;
2413 if (rt->state == STATE_STOPPED)
2417 RTMPPacket rpkt = { 0 };
2418 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2419 rt->in_chunk_size, &rt->prev_pkt[0],
2420 &rt->nb_prev_pkt[0])) <= 0) {
2422 return AVERROR(EAGAIN);
2424 return AVERROR(EIO);
2428 // Track timestamp for later use
2429 rt->last_timestamp = rpkt.timestamp;
2431 rt->bytes_read += ret;
2432 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2433 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2434 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2436 rt->last_bytes_read = rt->bytes_read;
2439 ret = rtmp_parse_result(s, rt, &rpkt);
2441 // At this point we must check if we are in the seek state and continue
2442 // with the next packet. handle_invoke will get us out of this state
2443 // when the right message is encountered
2444 if (rt->state == STATE_SEEKING) {
2445 ff_rtmp_packet_destroy(&rpkt);
2446 // We continue, let the natural flow of things happen:
2447 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2451 if (ret < 0) {//serious error in current packet
2452 ff_rtmp_packet_destroy(&rpkt);
2455 if (rt->do_reconnect && for_header) {
2456 ff_rtmp_packet_destroy(&rpkt);
2459 if (rt->state == STATE_STOPPED) {
2460 ff_rtmp_packet_destroy(&rpkt);
2463 if (for_header && (rt->state == STATE_PLAYING ||
2464 rt->state == STATE_PUBLISHING ||
2465 rt->state == STATE_SENDING ||
2466 rt->state == STATE_RECEIVING)) {
2467 ff_rtmp_packet_destroy(&rpkt);
2470 if (!rpkt.size || !rt->is_input) {
2471 ff_rtmp_packet_destroy(&rpkt);
2474 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2475 ret = append_flv_data(rt, &rpkt, 0);
2476 ff_rtmp_packet_destroy(&rpkt);
2478 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2479 ret = handle_notify(s, &rpkt);
2480 ff_rtmp_packet_destroy(&rpkt);
2482 } else if (rpkt.type == RTMP_PT_METADATA) {
2483 ret = handle_metadata(rt, &rpkt);
2484 ff_rtmp_packet_destroy(&rpkt);
2487 ff_rtmp_packet_destroy(&rpkt);
2491 static int rtmp_close(URLContext *h)
2493 RTMPContext *rt = h->priv_data;
2496 if (!rt->is_input) {
2497 rt->flv_data = NULL;
2498 if (rt->out_pkt.size)
2499 ff_rtmp_packet_destroy(&rt->out_pkt);
2500 if (rt->state > STATE_FCPUBLISH)
2501 ret = gen_fcunpublish_stream(h, rt);
2503 if (rt->state > STATE_HANDSHAKED)
2504 ret = gen_delete_stream(h, rt);
2505 for (i = 0; i < 2; i++) {
2506 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2507 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2508 av_freep(&rt->prev_pkt[i]);
2511 free_tracked_methods(rt);
2512 av_freep(&rt->flv_data);
2513 ffurl_close(rt->stream);
2518 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2519 * demuxer about the duration of the stream.
2521 * This should only be done if there was no real onMetadata packet sent by the
2522 * server at the start of the stream and if we were able to retrieve a valid
2523 * duration via a getStreamLength call.
2525 * @return 0 for successful operation, negative value in case of error
2527 static int inject_fake_duration_metadata(RTMPContext *rt)
2529 // We need to insert the metadata packet directly after the FLV
2530 // header, i.e. we need to move all other already read data by the
2531 // size of our fake metadata packet.
2534 // Keep old flv_data pointer
2535 uint8_t* old_flv_data = rt->flv_data;
2536 // Allocate a new flv_data pointer with enough space for the additional package
2537 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2538 rt->flv_data = old_flv_data;
2539 return AVERROR(ENOMEM);
2543 memcpy(rt->flv_data, old_flv_data, 13);
2544 // Copy remaining packets
2545 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2546 // Increase the size by the injected packet
2548 // Delete the old FLV data
2549 av_freep(&old_flv_data);
2551 p = rt->flv_data + 13;
2552 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2553 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2554 bytestream_put_be24(&p, 0); // timestamp
2555 bytestream_put_be32(&p, 0); // reserved
2557 // first event name as a string
2558 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2559 // "onMetaData" as AMF string
2560 bytestream_put_be16(&p, 10);
2561 bytestream_put_buffer(&p, "onMetaData", 10);
2563 // mixed array (hash) with size and string/type/data tuples
2564 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2565 bytestream_put_be32(&p, 1); // metadata_count
2567 // "duration" as AMF string
2568 bytestream_put_be16(&p, 8);
2569 bytestream_put_buffer(&p, "duration", 8);
2570 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2571 bytestream_put_be64(&p, av_double2int(rt->duration));
2574 bytestream_put_be16(&p, 0); // Empty string
2575 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2576 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2582 * Open RTMP connection and verify that the stream can be played.
2584 * URL syntax: rtmp://server[:port][/app][/playpath]
2585 * where 'app' is first one or two directories in the path
2586 * (e.g. /ondemand/, /flash/live/, etc.)
2587 * and 'playpath' is a file name (the rest of the path,
2588 * may be prefixed with "mp4:")
2590 static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2592 RTMPContext *rt = s->priv_data;
2593 char proto[8], hostname[256], path[1024], auth[100], *fname;
2594 char *old_app, *qmark, *n, fname_buffer[1024];
2599 if (rt->listen_timeout > 0)
2602 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2604 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2605 hostname, sizeof(hostname), &port,
2606 path, sizeof(path), s->filename);
2608 n = strchr(path, ' ');
2610 av_log(s, AV_LOG_WARNING,
2611 "Detected librtmp style URL parameters, these aren't supported "
2612 "by the libavformat internal RTMP handler currently enabled. "
2613 "See the documentation for the correct way to pass parameters.\n");
2614 *n = '\0'; // Trim not supported part
2618 char *ptr = strchr(auth, ':');
2621 av_strlcpy(rt->username, auth, sizeof(rt->username));
2622 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2626 if (rt->listen && strcmp(proto, "rtmp")) {
2627 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2629 return AVERROR(EINVAL);
2631 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2632 if (!strcmp(proto, "rtmpts"))
2633 av_dict_set(opts, "ffrtmphttp_tls", "1", 1);
2635 /* open the http tunneling connection */
2636 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2637 } else if (!strcmp(proto, "rtmps")) {
2638 /* open the tls connection */
2640 port = RTMPS_DEFAULT_PORT;
2641 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2642 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2643 if (!strcmp(proto, "rtmpte"))
2644 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2646 /* open the encrypted connection */
2647 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2650 /* open the tcp connection */
2652 port = RTMP_DEFAULT_PORT;
2654 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2655 "?listen&listen_timeout=%d",
2656 rt->listen_timeout * 1000);
2658 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2662 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2663 &s->interrupt_callback, opts,
2664 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2665 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2669 if (rt->swfverify) {
2670 if ((ret = rtmp_calc_swfhash(s)) < 0)
2674 rt->state = STATE_START;
2675 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2677 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2680 rt->out_chunk_size = 128;
2681 rt->in_chunk_size = 128; // Probably overwritten later
2682 rt->state = STATE_HANDSHAKED;
2684 // Keep the application name when it has been defined by the user.
2687 rt->app = av_malloc(APP_MAX_LENGTH);
2689 ret = AVERROR(ENOMEM);
2693 //extract "app" part from path
2694 qmark = strchr(path, '?');
2695 if (qmark && strstr(qmark, "slist=")) {
2697 // After slist we have the playpath, the full path is used as app
2698 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2699 fname = strstr(path, "slist=") + 6;
2700 // Strip any further query parameters from fname
2701 amp = strchr(fname, '&');
2703 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2704 sizeof(fname_buffer)));
2705 fname = fname_buffer;
2707 } else if (!strncmp(path, "/ondemand/", 10)) {
2709 memcpy(rt->app, "ondemand", 9);
2711 char *next = *path ? path + 1 : path;
2712 char *p = strchr(next, '/');
2715 // If name of application has been defined by the user, assume that
2716 // playpath is provided in the URL
2720 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2723 // make sure we do not mismatch a playpath for an application instance
2724 char *c = strchr(p + 1, ':');
2725 fname = strchr(p + 1, '/');
2726 if (!fname || (c && c < fname)) {
2728 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2731 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2737 // The name of application has been defined by the user, override it.
2738 if (strlen(old_app) >= APP_MAX_LENGTH) {
2739 ret = AVERROR(EINVAL);
2746 if (!rt->playpath) {
2747 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2748 if (!rt->playpath) {
2749 ret = AVERROR(ENOMEM);
2754 int len = strlen(fname);
2755 if (!strchr(fname, ':') && len >= 4 &&
2756 (!strcmp(fname + len - 4, ".f4v") ||
2757 !strcmp(fname + len - 4, ".mp4"))) {
2758 memcpy(rt->playpath, "mp4:", 5);
2760 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2761 fname[len - 4] = '\0';
2762 rt->playpath[0] = 0;
2764 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2766 rt->playpath[0] = '\0';
2771 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2773 ret = AVERROR(ENOMEM);
2776 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2777 port, "/%s", rt->app);
2780 if (!rt->flashver) {
2781 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2782 if (!rt->flashver) {
2783 ret = AVERROR(ENOMEM);
2787 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2788 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2789 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2791 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2792 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2796 rt->receive_report_size = 1048576;
2800 rt->received_metadata = 0;
2801 rt->last_bytes_read = 0;
2802 rt->max_sent_unacked = 2500000;
2805 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2806 proto, path, rt->app, rt->playpath);
2808 if ((ret = gen_connect(s, rt)) < 0)
2811 if ((ret = read_connect(s, s->priv_data)) < 0)
2816 ret = get_packet(s, 1);
2817 } while (ret == AVERROR(EAGAIN));
2821 if (rt->do_reconnect) {
2823 ffurl_close(rt->stream);
2825 rt->do_reconnect = 0;
2827 for (i = 0; i < 2; i++)
2828 memset(rt->prev_pkt[i], 0,
2829 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2830 free_tracked_methods(rt);
2835 // generate FLV header for demuxer
2837 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2840 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2842 // Read packets until we reach the first A/V packet or read metadata.
2843 // If there was a metadata package in front of the A/V packets, we can
2844 // build the FLV header from this. If we do not receive any metadata,
2845 // the FLV decoder will allocate the needed streams when their first
2846 // audio or video packet arrives.
2847 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2848 if ((ret = get_packet(s, 0)) < 0)
2852 // Either after we have read the metadata or (if there is none) the
2853 // first packet of an A/V stream, we have a better knowledge about the
2854 // streams, so set the FLV header accordingly.
2855 if (rt->has_audio) {
2856 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2858 if (rt->has_video) {
2859 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2862 // If we received the first packet of an A/V stream and no metadata but
2863 // the server returned a valid duration, create a fake metadata packet
2864 // to inform the FLV decoder about the duration.
2865 if (!rt->received_metadata && rt->duration > 0) {
2866 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2871 rt->flv_data = NULL;
2873 rt->skip_bytes = 13;
2876 s->max_packet_size = rt->stream->max_packet_size;
2886 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2888 RTMPContext *rt = s->priv_data;
2889 int orig_size = size;
2893 int data_left = rt->flv_size - rt->flv_off;
2895 if (data_left >= size) {
2896 memcpy(buf, rt->flv_data + rt->flv_off, size);
2897 rt->flv_off += size;
2900 if (data_left > 0) {
2901 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2904 rt->flv_off = rt->flv_size;
2907 if ((ret = get_packet(s, 0)) < 0)
2913 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2916 RTMPContext *rt = s->priv_data;
2918 av_log(s, AV_LOG_DEBUG,
2919 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2920 stream_index, timestamp, flags);
2921 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2922 av_log(s, AV_LOG_ERROR,
2923 "Unable to send seek command on stream index %d at timestamp "
2924 "%"PRId64" with flags %08x\n",
2925 stream_index, timestamp, flags);
2928 rt->flv_off = rt->flv_size;
2929 rt->state = STATE_SEEKING;
2933 static int rtmp_pause(URLContext *s, int pause)
2935 RTMPContext *rt = s->priv_data;
2937 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2938 rt->last_timestamp);
2939 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2940 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2941 rt->last_timestamp);
2947 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2949 RTMPContext *rt = s->priv_data;
2950 int size_temp = size;
2951 int pktsize, pkttype, copy;
2953 const uint8_t *buf_temp = buf;
2958 if (rt->skip_bytes) {
2959 int skip = FFMIN(rt->skip_bytes, size_temp);
2962 rt->skip_bytes -= skip;
2966 if (rt->flv_header_bytes < RTMP_HEADER) {
2967 const uint8_t *header = rt->flv_header;
2968 int channel = RTMP_AUDIO_CHANNEL;
2970 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2971 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2972 rt->flv_header_bytes += copy;
2974 if (rt->flv_header_bytes < RTMP_HEADER)
2977 pkttype = bytestream_get_byte(&header);
2978 pktsize = bytestream_get_be24(&header);
2979 ts = bytestream_get_be24(&header);
2980 ts |= bytestream_get_byte(&header) << 24;
2981 bytestream_get_be24(&header);
2982 rt->flv_size = pktsize;
2984 if (pkttype == RTMP_PT_VIDEO)
2985 channel = RTMP_VIDEO_CHANNEL;
2987 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2988 pkttype == RTMP_PT_NOTIFY) {
2989 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2990 &rt->nb_prev_pkt[1],
2993 // Force sending a full 12 bytes header by clearing the
2994 // channel id, to make it not match a potential earlier
2995 // packet in the same channel.
2996 rt->prev_pkt[1][channel].channel_id = 0;
2999 //this can be a big packet, it's better to send it right here
3000 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3001 pkttype, ts, pktsize)) < 0)
3004 rt->out_pkt.extra = rt->stream_id;
3005 rt->flv_data = rt->out_pkt.data;
3008 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3009 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3010 rt->flv_off += copy;
3013 if (rt->flv_off == rt->flv_size) {
3016 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3017 // For onMetaData and |RtmpSampleAccess packets, we want
3018 // @setDataFrame prepended to the packet before it gets sent.
3019 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3021 uint8_t commandbuffer[64];
3025 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3026 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3028 if (!strcmp(commandbuffer, "onMetaData") ||
3029 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3031 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3032 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3035 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3036 rt->out_pkt.size += 16;
3037 ptr = rt->out_pkt.data;
3038 ff_amf_write_string(&ptr, "@setDataFrame");
3043 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3047 rt->flv_header_bytes = 0;
3048 rt->flv_nb_packets++;
3050 } while (buf_temp - buf < size);
3052 if (rt->flv_nb_packets < rt->flush_interval)
3054 rt->flv_nb_packets = 0;
3056 /* set stream into nonblocking mode */
3057 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3059 /* try to read one byte from the stream */
3060 ret = ffurl_read(rt->stream, &c, 1);
3062 /* switch the stream back into blocking mode */
3063 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3065 if (ret == AVERROR(EAGAIN)) {
3066 /* no incoming data to handle */
3068 } else if (ret < 0) {
3070 } else if (ret == 1) {
3071 RTMPPacket rpkt = { 0 };
3073 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3076 &rt->nb_prev_pkt[0], c)) <= 0)
3079 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3082 ff_rtmp_packet_destroy(&rpkt);
3088 #define OFFSET(x) offsetof(RTMPContext, x)
3089 #define DEC AV_OPT_FLAG_DECODING_PARAM
3090 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3092 static const AVOption rtmp_options[] = {
3093 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3094 {"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},
3095 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3096 {"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},
3097 {"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},
3098 {"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"},
3099 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3100 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3101 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3102 {"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},
3103 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3104 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3105 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3106 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3107 {"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},
3108 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3109 {"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},
3110 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3111 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3112 {"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" },
3116 #define RTMP_PROTOCOL(flavor) \
3117 static const AVClass flavor##_class = { \
3118 .class_name = #flavor, \
3119 .item_name = av_default_item_name, \
3120 .option = rtmp_options, \
3121 .version = LIBAVUTIL_VERSION_INT, \
3124 const URLProtocol ff_##flavor##_protocol = { \
3126 .url_open2 = rtmp_open, \
3127 .url_read = rtmp_read, \
3128 .url_read_seek = rtmp_seek, \
3129 .url_read_pause = rtmp_pause, \
3130 .url_write = rtmp_write, \
3131 .url_close = rtmp_close, \
3132 .priv_data_size = sizeof(RTMPContext), \
3133 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3134 .priv_data_class= &flavor##_class, \
3139 RTMP_PROTOCOL(rtmpe)
3140 RTMP_PROTOCOL(rtmps)
3141 RTMP_PROTOCOL(rtmpt)
3142 RTMP_PROTOCOL(rtmpte)
3143 RTMP_PROTOCOL(rtmpts)