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 TCURL_MAX_LENGTH 1024
52 #define FLASHVER_MAX_LENGTH 64
53 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
54 #define RTMP_HEADER 11
56 /** RTMP protocol handler state */
58 STATE_START, ///< client has not done anything yet
59 STATE_HANDSHAKED, ///< client has performed handshake
60 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
61 STATE_PLAYING, ///< client has started receiving multimedia data from server
62 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
63 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
64 STATE_RECEIVING, ///< received a publish command (for input)
65 STATE_SENDING, ///< received a play command (for output)
66 STATE_STOPPED, ///< the broadcast has been stopped
69 typedef struct TrackedMethod {
74 /** protocol handler context */
75 typedef struct RTMPContext {
77 URLContext* stream; ///< TCP stream used in interactions with RTMP server
78 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
79 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
80 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
81 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
82 int is_input; ///< input/output flag
83 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
84 int live; ///< 0: recorded, -1: live, -2: both
85 char *app; ///< name of application
86 char *conn; ///< append arbitrary AMF data to the Connect message
87 ClientState state; ///< current state
88 int stream_id; ///< ID assigned by the server for the stream
89 uint8_t* flv_data; ///< buffer with data for demuxer
90 int flv_size; ///< current buffer size
91 int flv_off; ///< number of bytes read from current buffer
92 int flv_nb_packets; ///< number of flv packets published
93 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
94 uint32_t receive_report_size; ///< number of bytes after which we should report the number of received bytes to the peer
95 uint64_t bytes_read; ///< number of bytes read from server
96 uint64_t last_bytes_read; ///< number of bytes read last reported to server
97 uint32_t last_timestamp; ///< last timestamp received in a packet
98 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
99 int has_audio; ///< presence of audio data
100 int has_video; ///< presence of video data
101 int received_metadata; ///< Indicates if we have received metadata about the streams
102 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
103 int flv_header_bytes; ///< number of initialized bytes in flv_header
104 int nb_invokes; ///< keeps track of invoke messages
105 char* tcurl; ///< url of the target stream
106 char* flashver; ///< version of the flash plugin
107 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
108 int swfhash_len; ///< length of the SHA256 hash
109 int swfsize; ///< size of the decompressed SWF file
110 char* swfurl; ///< url of the swf player
111 char* swfverify; ///< URL to player swf file, compute hash/size automatically
112 char swfverification[42]; ///< hash of the SWF verification
113 char* pageurl; ///< url of the web page
114 char* subscribe; ///< name of live stream to subscribe
115 int max_sent_unacked; ///< max unacked sent bytes
116 int client_buffer_time; ///< client buffer time in ms
117 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
118 int encrypted; ///< use an encrypted connection (RTMPE only)
119 TrackedMethod*tracked_methods; ///< tracked methods buffer
120 int nb_tracked_methods; ///< number of tracked methods
121 int tracked_methods_size; ///< size of the tracked methods buffer
122 int listen; ///< listen mode flag
123 int listen_timeout; ///< listen timeout to wait for new connections
124 int nb_streamid; ///< The next stream id to return on createStream calls
125 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
128 char auth_params[500];
133 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
134 /** Client key used for digest signing */
135 static const uint8_t rtmp_player_key[] = {
136 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
137 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
139 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
140 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
141 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
144 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
145 /** Key used for RTMP server digest signing */
146 static const uint8_t rtmp_server_key[] = {
147 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
148 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
149 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
151 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
152 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
153 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
156 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
157 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt);
158 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt);
160 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
164 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
165 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
166 if ((err = av_reallocp_array(&rt->tracked_methods, rt->tracked_methods_size,
167 sizeof(*rt->tracked_methods))) < 0) {
168 rt->nb_tracked_methods = 0;
169 rt->tracked_methods_size = 0;
174 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
175 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
176 return AVERROR(ENOMEM);
177 rt->tracked_methods[rt->nb_tracked_methods].id = id;
178 rt->nb_tracked_methods++;
183 static void del_tracked_method(RTMPContext *rt, int index)
185 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
186 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
187 rt->nb_tracked_methods--;
190 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
191 char **tracked_method)
193 RTMPContext *rt = s->priv_data;
199 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
200 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
203 for (i = 0; i < rt->nb_tracked_methods; i++) {
204 if (rt->tracked_methods[i].id != pkt_id)
207 *tracked_method = rt->tracked_methods[i].name;
208 del_tracked_method(rt, i);
215 static void free_tracked_methods(RTMPContext *rt)
219 for (i = 0; i < rt->nb_tracked_methods; i ++)
220 av_freep(&rt->tracked_methods[i].name);
221 av_freep(&rt->tracked_methods);
222 rt->tracked_methods_size = 0;
223 rt->nb_tracked_methods = 0;
226 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
230 if (pkt->type == RTMP_PT_INVOKE && track) {
236 bytestream2_init(&gbc, pkt->data, pkt->size);
237 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
240 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
243 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
247 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
248 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
250 ff_rtmp_packet_destroy(pkt);
254 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
259 /* The type must be B for Boolean, N for number, S for string, O for
260 * object, or Z for null. For Booleans the data must be either 0 or 1 for
261 * FALSE or TRUE, respectively. Likewise for Objects the data must be
262 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
263 * may be named, by prefixing the type with 'N' and specifying the name
264 * before the value (ie. NB:myFlag:1). This option may be used multiple times
265 * to construct arbitrary AMF sequences. */
266 if (param[0] && param[1] == ':') {
269 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
272 value = strchr(field, ':');
278 ff_amf_write_field_name(p, field);
285 ff_amf_write_bool(p, value[0] != '0');
288 ff_amf_write_string(p, value);
291 ff_amf_write_number(p, strtod(value, NULL));
294 ff_amf_write_null(p);
298 ff_amf_write_object_start(p);
300 ff_amf_write_object_end(p);
310 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
311 return AVERROR(EINVAL);
315 * Generate 'connect' call and send it to the server.
317 static int gen_connect(URLContext *s, RTMPContext *rt)
323 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
324 0, 4096 + APP_MAX_LENGTH)) < 0)
329 ff_amf_write_string(&p, "connect");
330 ff_amf_write_number(&p, ++rt->nb_invokes);
331 ff_amf_write_object_start(&p);
332 ff_amf_write_field_name(&p, "app");
333 ff_amf_write_string2(&p, rt->app, rt->auth_params);
336 ff_amf_write_field_name(&p, "type");
337 ff_amf_write_string(&p, "nonprivate");
339 ff_amf_write_field_name(&p, "flashVer");
340 ff_amf_write_string(&p, rt->flashver);
342 if (rt->swfurl || rt->swfverify) {
343 ff_amf_write_field_name(&p, "swfUrl");
345 ff_amf_write_string(&p, rt->swfurl);
347 ff_amf_write_string(&p, rt->swfverify);
350 ff_amf_write_field_name(&p, "tcUrl");
351 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
353 ff_amf_write_field_name(&p, "fpad");
354 ff_amf_write_bool(&p, 0);
355 ff_amf_write_field_name(&p, "capabilities");
356 ff_amf_write_number(&p, 15.0);
358 /* Tell the server we support all the audio codecs except
359 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
360 * which are unused in the RTMP protocol implementation. */
361 ff_amf_write_field_name(&p, "audioCodecs");
362 ff_amf_write_number(&p, 4071.0);
363 ff_amf_write_field_name(&p, "videoCodecs");
364 ff_amf_write_number(&p, 252.0);
365 ff_amf_write_field_name(&p, "videoFunction");
366 ff_amf_write_number(&p, 1.0);
369 ff_amf_write_field_name(&p, "pageUrl");
370 ff_amf_write_string(&p, rt->pageurl);
373 ff_amf_write_object_end(&p);
376 char *param = rt->conn;
378 // Write arbitrary AMF data to the Connect message.
381 param += strspn(param, " ");
384 sep = strchr(param, ' ');
387 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
388 // Invalid AMF parameter.
389 ff_rtmp_packet_destroy(&pkt);
400 pkt.size = p - pkt.data;
402 return rtmp_send_packet(rt, &pkt, 1);
406 #define RTMP_CTRL_ABORT_MESSAGE (2)
408 static int read_connect(URLContext *s, RTMPContext *rt)
410 RTMPPacket pkt = { 0 };
420 // handle RTMP Protocol Control Messages
422 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
423 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
426 ff_rtmp_packet_dump(s, &pkt);
428 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
429 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
430 ff_rtmp_packet_destroy(&pkt);
433 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
434 av_log(s, AV_LOG_ERROR, "received abort message\n");
435 ff_rtmp_packet_destroy(&pkt);
436 return AVERROR_UNKNOWN;
437 } else if (pkt.type == RTMP_PT_BYTES_READ) {
438 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
439 } else if (pkt.type == RTMP_PT_WINDOW_ACK_SIZE) {
440 if ((ret = handle_window_ack_size(s, &pkt)) < 0) {
441 ff_rtmp_packet_destroy(&pkt);
444 } else if (pkt.type == RTMP_PT_SET_PEER_BW) {
445 if ((ret = handle_set_peer_bw(s, &pkt)) < 0) {
446 ff_rtmp_packet_destroy(&pkt);
449 } else if (pkt.type == RTMP_PT_INVOKE) {
450 // received RTMP Command Message
453 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
455 ff_rtmp_packet_destroy(&pkt);
459 bytestream2_init(&gbc, cp, pkt.size);
460 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
461 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
462 ff_rtmp_packet_destroy(&pkt);
463 return AVERROR_INVALIDDATA;
465 if (strcmp(command, "connect")) {
466 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
467 ff_rtmp_packet_destroy(&pkt);
468 return AVERROR_INVALIDDATA;
470 ret = ff_amf_read_number(&gbc, &seqnum);
472 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
473 /* Here one could parse an AMF Object with data as flashVers and others. */
474 ret = ff_amf_get_field_value(gbc.buffer,
475 gbc.buffer + bytestream2_get_bytes_left(&gbc),
476 "app", tmpstr, sizeof(tmpstr));
478 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
479 if (!ret && strcmp(tmpstr, rt->app))
480 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
482 ff_rtmp_packet_destroy(&pkt);
484 // Send Window Acknowledgement Size (as defined in specification)
485 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
486 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
489 // Inform the peer about how often we want acknowledgements about what
490 // we send. (We don't check for the acknowledgements currently.)
491 bytestream_put_be32(&p, rt->max_sent_unacked);
492 pkt.size = p - pkt.data;
493 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
494 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
495 ff_rtmp_packet_destroy(&pkt);
498 // Set Peer Bandwidth
499 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
500 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
503 // Tell the peer to only send this many bytes unless it gets acknowledgements.
504 // This could be any arbitrary value we want here.
505 bytestream_put_be32(&p, rt->max_sent_unacked);
506 bytestream_put_byte(&p, 2); // dynamic
507 pkt.size = p - pkt.data;
508 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
509 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
510 ff_rtmp_packet_destroy(&pkt);
515 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
516 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
520 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
521 bytestream_put_be32(&p, 0); // Stream 0
522 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
523 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
524 ff_rtmp_packet_destroy(&pkt);
529 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
530 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
534 bytestream_put_be32(&p, rt->out_chunk_size);
535 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
536 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
537 ff_rtmp_packet_destroy(&pkt);
541 // Send _result NetConnection.Connect.Success to connect
542 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
544 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
548 ff_amf_write_string(&p, "_result");
549 ff_amf_write_number(&p, seqnum);
551 ff_amf_write_object_start(&p);
552 ff_amf_write_field_name(&p, "fmsVer");
553 ff_amf_write_string(&p, "FMS/3,0,1,123");
554 ff_amf_write_field_name(&p, "capabilities");
555 ff_amf_write_number(&p, 31);
556 ff_amf_write_object_end(&p);
558 ff_amf_write_object_start(&p);
559 ff_amf_write_field_name(&p, "level");
560 ff_amf_write_string(&p, "status");
561 ff_amf_write_field_name(&p, "code");
562 ff_amf_write_string(&p, "NetConnection.Connect.Success");
563 ff_amf_write_field_name(&p, "description");
564 ff_amf_write_string(&p, "Connection succeeded.");
565 ff_amf_write_field_name(&p, "objectEncoding");
566 ff_amf_write_number(&p, 0);
567 ff_amf_write_object_end(&p);
569 pkt.size = p - pkt.data;
570 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
571 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
572 ff_rtmp_packet_destroy(&pkt);
576 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
577 RTMP_PT_INVOKE, 0, 30)) < 0)
580 ff_amf_write_string(&p, "onBWDone");
581 ff_amf_write_number(&p, 0);
582 ff_amf_write_null(&p);
583 ff_amf_write_number(&p, 8192);
584 pkt.size = p - pkt.data;
585 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
586 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
587 ff_rtmp_packet_destroy(&pkt);
593 * Generate 'releaseStream' call and send it to the server. It should make
594 * the server release some channel for media streams.
596 static int gen_release_stream(URLContext *s, RTMPContext *rt)
602 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
603 0, 29 + strlen(rt->playpath))) < 0)
606 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
608 ff_amf_write_string(&p, "releaseStream");
609 ff_amf_write_number(&p, ++rt->nb_invokes);
610 ff_amf_write_null(&p);
611 ff_amf_write_string(&p, rt->playpath);
613 return rtmp_send_packet(rt, &pkt, 1);
617 * Generate 'FCPublish' call and send it to the server. It should make
618 * the server prepare for receiving media streams.
620 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
626 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
627 0, 25 + strlen(rt->playpath))) < 0)
630 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
632 ff_amf_write_string(&p, "FCPublish");
633 ff_amf_write_number(&p, ++rt->nb_invokes);
634 ff_amf_write_null(&p);
635 ff_amf_write_string(&p, rt->playpath);
637 return rtmp_send_packet(rt, &pkt, 1);
641 * Generate 'FCUnpublish' call and send it to the server. It should make
642 * the server destroy stream.
644 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
650 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
651 0, 27 + strlen(rt->playpath))) < 0)
654 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
656 ff_amf_write_string(&p, "FCUnpublish");
657 ff_amf_write_number(&p, ++rt->nb_invokes);
658 ff_amf_write_null(&p);
659 ff_amf_write_string(&p, rt->playpath);
661 return rtmp_send_packet(rt, &pkt, 0);
665 * Generate 'createStream' call and send it to the server. It should make
666 * the server allocate some channel for media streams.
668 static int gen_create_stream(URLContext *s, RTMPContext *rt)
674 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
676 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
681 ff_amf_write_string(&p, "createStream");
682 ff_amf_write_number(&p, ++rt->nb_invokes);
683 ff_amf_write_null(&p);
685 return rtmp_send_packet(rt, &pkt, 1);
690 * Generate 'deleteStream' call and send it to the server. It should make
691 * the server remove some channel for media streams.
693 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
699 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
701 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
706 ff_amf_write_string(&p, "deleteStream");
707 ff_amf_write_number(&p, ++rt->nb_invokes);
708 ff_amf_write_null(&p);
709 ff_amf_write_number(&p, rt->stream_id);
711 return rtmp_send_packet(rt, &pkt, 0);
715 * Generate 'getStreamLength' call and send it to the server. If the server
716 * knows the duration of the selected stream, it will reply with the duration
719 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
725 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
726 0, 31 + strlen(rt->playpath))) < 0)
730 ff_amf_write_string(&p, "getStreamLength");
731 ff_amf_write_number(&p, ++rt->nb_invokes);
732 ff_amf_write_null(&p);
733 ff_amf_write_string(&p, rt->playpath);
735 return rtmp_send_packet(rt, &pkt, 1);
739 * Generate client buffer time and send it to the server.
741 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
747 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
752 bytestream_put_be16(&p, 3); // SetBuffer Length
753 bytestream_put_be32(&p, rt->stream_id);
754 bytestream_put_be32(&p, rt->client_buffer_time);
756 return rtmp_send_packet(rt, &pkt, 0);
760 * Generate 'play' call and send it to the server, then ping the server
761 * to start actual playing.
763 static int gen_play(URLContext *s, RTMPContext *rt)
769 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
771 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
772 0, 29 + strlen(rt->playpath))) < 0)
775 pkt.extra = rt->stream_id;
778 ff_amf_write_string(&p, "play");
779 ff_amf_write_number(&p, ++rt->nb_invokes);
780 ff_amf_write_null(&p);
781 ff_amf_write_string(&p, rt->playpath);
782 ff_amf_write_number(&p, rt->live * 1000);
784 return rtmp_send_packet(rt, &pkt, 1);
787 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
793 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
796 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
799 pkt.extra = rt->stream_id;
802 ff_amf_write_string(&p, "seek");
803 ff_amf_write_number(&p, 0); //no tracking back responses
804 ff_amf_write_null(&p); //as usual, the first null param
805 ff_amf_write_number(&p, timestamp); //where we want to jump
807 return rtmp_send_packet(rt, &pkt, 1);
811 * Generate a pause packet that either pauses or unpauses the current stream.
813 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
819 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
822 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
825 pkt.extra = rt->stream_id;
828 ff_amf_write_string(&p, "pause");
829 ff_amf_write_number(&p, 0); //no tracking back responses
830 ff_amf_write_null(&p); //as usual, the first null param
831 ff_amf_write_bool(&p, pause); // pause or unpause
832 ff_amf_write_number(&p, timestamp); //where we pause the stream
834 return rtmp_send_packet(rt, &pkt, 1);
838 * Generate 'publish' call and send it to the server.
840 static int gen_publish(URLContext *s, RTMPContext *rt)
846 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
848 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
849 0, 30 + strlen(rt->playpath))) < 0)
852 pkt.extra = rt->stream_id;
855 ff_amf_write_string(&p, "publish");
856 ff_amf_write_number(&p, ++rt->nb_invokes);
857 ff_amf_write_null(&p);
858 ff_amf_write_string(&p, rt->playpath);
859 ff_amf_write_string(&p, "live");
861 return rtmp_send_packet(rt, &pkt, 1);
865 * Generate ping reply and send it to the server.
867 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
873 if (ppkt->size < 6) {
874 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
876 return AVERROR_INVALIDDATA;
879 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
880 ppkt->timestamp + 1, 6)) < 0)
884 bytestream_put_be16(&p, 7); // PingResponse
885 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
887 return rtmp_send_packet(rt, &pkt, 0);
891 * Generate SWF verification message and send it to the server.
893 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
899 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
900 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
905 bytestream_put_be16(&p, 27);
906 memcpy(p, rt->swfverification, 42);
908 return rtmp_send_packet(rt, &pkt, 0);
912 * Generate window acknowledgement size message and send it to the server.
914 static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
920 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
925 bytestream_put_be32(&p, rt->max_sent_unacked);
927 return rtmp_send_packet(rt, &pkt, 0);
931 * Generate check bandwidth message and send it to the server.
933 static int gen_check_bw(URLContext *s, RTMPContext *rt)
939 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
944 ff_amf_write_string(&p, "_checkbw");
945 ff_amf_write_number(&p, ++rt->nb_invokes);
946 ff_amf_write_null(&p);
948 return rtmp_send_packet(rt, &pkt, 1);
952 * Generate report on bytes read so far and send it to the server.
954 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
960 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
965 bytestream_put_be32(&p, rt->bytes_read);
967 return rtmp_send_packet(rt, &pkt, 0);
970 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
971 const char *subscribe)
977 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
978 0, 27 + strlen(subscribe))) < 0)
982 ff_amf_write_string(&p, "FCSubscribe");
983 ff_amf_write_number(&p, ++rt->nb_invokes);
984 ff_amf_write_null(&p);
985 ff_amf_write_string(&p, subscribe);
987 return rtmp_send_packet(rt, &pkt, 1);
991 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
992 * will be stored) into that packet.
994 * @param buf handshake data (1536 bytes)
995 * @param encrypted use an encrypted connection (RTMPE)
996 * @return offset to the digest inside input data
998 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1000 int ret, digest_pos;
1003 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1005 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1007 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1008 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1017 * Verify that the received server response has the expected digest value.
1019 * @param buf handshake data received from the server (1536 bytes)
1020 * @param off position to search digest offset from
1021 * @return 0 if digest is valid, digest position otherwise
1023 static int rtmp_validate_digest(uint8_t *buf, int off)
1026 int ret, digest_pos;
1028 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1030 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1031 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1036 if (!memcmp(digest, buf + digest_pos, 32))
1041 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1047 if (rt->swfhash_len != 32) {
1048 av_log(s, AV_LOG_ERROR,
1049 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1050 return AVERROR(EINVAL);
1053 p = &rt->swfverification[0];
1054 bytestream_put_byte(&p, 1);
1055 bytestream_put_byte(&p, 1);
1056 bytestream_put_be32(&p, rt->swfsize);
1057 bytestream_put_be32(&p, rt->swfsize);
1059 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1066 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1067 uint8_t **out_data, int64_t *out_size)
1069 z_stream zs = { 0 };
1074 zs.avail_in = in_size;
1075 zs.next_in = in_data;
1076 ret = inflateInit(&zs);
1078 return AVERROR_UNKNOWN;
1081 uint8_t tmp_buf[16384];
1083 zs.avail_out = sizeof(tmp_buf);
1084 zs.next_out = tmp_buf;
1086 ret = inflate(&zs, Z_NO_FLUSH);
1087 if (ret != Z_OK && ret != Z_STREAM_END) {
1088 ret = AVERROR_UNKNOWN;
1092 size = sizeof(tmp_buf) - zs.avail_out;
1093 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1094 ret = AVERROR(ENOMEM);
1099 memcpy(*out_data + *out_size, tmp_buf, size);
1101 } while (zs.avail_out == 0);
1109 static int rtmp_calc_swfhash(URLContext *s)
1111 RTMPContext *rt = s->priv_data;
1112 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1114 URLContext *stream = NULL;
1119 /* Get the SWF player file. */
1120 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1121 &s->interrupt_callback, NULL,
1122 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1123 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1127 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1132 if (!(in_data = av_malloc(in_size))) {
1133 ret = AVERROR(ENOMEM);
1137 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1141 ret = AVERROR_INVALIDDATA;
1145 if (!memcmp(in_data, "CWS", 3)) {
1148 /* Decompress the SWF player file using Zlib. */
1149 if (!(out_data = av_malloc(8))) {
1150 ret = AVERROR(ENOMEM);
1153 *in_data = 'F'; // magic stuff
1154 memcpy(out_data, in_data, 8);
1157 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1158 &out_data, &out_size)) < 0)
1163 av_log(s, AV_LOG_ERROR,
1164 "Zlib is required for decompressing the SWF player file.\n");
1165 ret = AVERROR(EINVAL);
1173 /* Compute the SHA256 hash of the SWF player file. */
1174 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1175 "Genuine Adobe Flash Player 001", 30,
1179 /* Set SWFVerification parameters. */
1180 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1181 rt->swfsize = swfsize;
1185 av_freep(&out_data);
1186 ffurl_close(stream);
1191 * Perform handshake with the server by means of exchanging pseudorandom data
1192 * signed with HMAC-SHA2 digest.
1194 * @return 0 if handshake succeeds, negative value otherwise
1196 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1199 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1200 3, // unencrypted data
1201 0, 0, 0, 0, // client uptime
1207 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1208 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1210 int server_pos, client_pos;
1211 uint8_t digest[32], signature[32];
1214 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1216 av_lfg_init(&rnd, 0xDEADC0DE);
1217 // generate handshake packet - 1536 bytes of pseudorandom data
1218 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1219 tosend[i] = av_lfg_get(&rnd) >> 24;
1221 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1222 /* When the client wants to use RTMPE, we have to change the command
1223 * byte to 0x06 which means to use encrypted data and we have to set
1224 * the flash version to at least 9.0.115.0. */
1231 /* Initialize the Diffie-Hellmann context and generate the public key
1232 * to send to the server. */
1233 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1237 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1241 if ((ret = ffurl_write(rt->stream, tosend,
1242 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1243 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1247 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1248 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1249 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1253 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1254 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1255 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1259 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1260 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1261 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1263 if (rt->is_input && serverdata[5] >= 3) {
1264 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1270 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1275 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1276 return AVERROR(EIO);
1280 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1281 * key are the last 32 bytes of the server handshake. */
1283 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1284 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1288 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1289 rtmp_server_key, sizeof(rtmp_server_key),
1294 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1295 0, digest, 32, signature);
1299 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1300 /* Compute the shared secret key sent by the server and initialize
1301 * the RC4 encryption. */
1302 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1303 tosend + 1, type)) < 0)
1306 /* Encrypt the signature received by the server. */
1307 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1310 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1311 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1312 return AVERROR(EIO);
1315 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1316 tosend[i] = av_lfg_get(&rnd) >> 24;
1317 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1318 rtmp_player_key, sizeof(rtmp_player_key),
1323 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1325 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1329 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1330 /* Encrypt the signature to be send to the server. */
1331 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1332 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1336 // write reply back to the server
1337 if ((ret = ffurl_write(rt->stream, tosend,
1338 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1341 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1342 /* Set RC4 keys for encryption and update the keystreams. */
1343 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1347 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1348 /* Compute the shared secret key sent by the server and initialize
1349 * the RC4 encryption. */
1350 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1351 tosend + 1, 1)) < 0)
1354 if (serverdata[0] == 9) {
1355 /* Encrypt the signature received by the server. */
1356 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1361 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1362 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1365 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1366 /* Set RC4 keys for encryption and update the keystreams. */
1367 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1375 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1376 uint32_t *second_int, char *arraydata,
1381 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1382 RTMP_HANDSHAKE_PACKET_SIZE);
1384 return AVERROR(EIO);
1385 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1386 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1387 " not following standard\n", (int)inoutsize);
1388 return AVERROR(EINVAL);
1391 *first_int = AV_RB32(arraydata);
1392 *second_int = AV_RB32(arraydata + 4);
1396 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1397 uint32_t second_int, char *arraydata, int size)
1401 AV_WB32(arraydata, first_int);
1402 AV_WB32(arraydata + 4, second_int);
1403 inoutsize = ffurl_write(rt->stream, arraydata,
1404 RTMP_HANDSHAKE_PACKET_SIZE);
1405 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1406 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1407 return AVERROR(EIO);
1414 * rtmp handshake server side
1416 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1418 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1420 uint32_t hs_my_epoch;
1421 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1422 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1429 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1430 if (inoutsize <= 0) {
1431 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1432 return AVERROR(EIO);
1435 if (buffer[0] != 3) {
1436 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1437 return AVERROR(EIO);
1439 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1440 av_log(s, AV_LOG_ERROR,
1441 "Unable to write answer - RTMP S0\n");
1442 return AVERROR(EIO);
1445 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1446 RTMP_HANDSHAKE_PACKET_SIZE);
1448 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1452 /* By now same epoch will be sent */
1453 hs_my_epoch = hs_epoch;
1454 /* Generate random */
1455 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1457 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1459 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1460 RTMP_HANDSHAKE_PACKET_SIZE);
1462 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1466 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1467 RTMP_HANDSHAKE_PACKET_SIZE);
1469 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1473 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1474 RTMP_HANDSHAKE_PACKET_SIZE);
1476 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1479 if (temp != hs_my_epoch)
1480 av_log(s, AV_LOG_WARNING,
1481 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1482 if (memcmp(buffer + 8, hs_s1 + 8,
1483 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1484 av_log(s, AV_LOG_WARNING,
1485 "Erroneous C2 Message random does not match up\n");
1490 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1492 RTMPContext *rt = s->priv_data;
1495 if (pkt->size < 4) {
1496 av_log(s, AV_LOG_ERROR,
1497 "Too short chunk size change packet (%d)\n",
1499 return AVERROR_INVALIDDATA;
1502 if (!rt->is_input) {
1503 /* Send the same chunk size change packet back to the server,
1504 * setting the outgoing chunk size to the same as the incoming one. */
1505 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1506 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1508 rt->out_chunk_size = AV_RB32(pkt->data);
1511 rt->in_chunk_size = AV_RB32(pkt->data);
1512 if (rt->in_chunk_size <= 0) {
1513 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1515 return AVERROR_INVALIDDATA;
1517 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1523 static int handle_user_control(URLContext *s, RTMPPacket *pkt)
1525 RTMPContext *rt = s->priv_data;
1528 if (pkt->size < 2) {
1529 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1531 return AVERROR_INVALIDDATA;
1534 t = AV_RB16(pkt->data);
1535 if (t == 6) { // PingRequest
1536 if ((ret = gen_pong(s, rt, pkt)) < 0)
1538 } else if (t == 26) {
1540 if ((ret = gen_swf_verification(s, rt)) < 0)
1543 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1550 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
1552 RTMPContext *rt = s->priv_data;
1554 if (pkt->size < 4) {
1555 av_log(s, AV_LOG_ERROR,
1556 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1558 return AVERROR_INVALIDDATA;
1561 // We currently don't check how much the peer has acknowledged of
1562 // what we have sent. To do that properly, we should call
1563 // gen_window_ack_size here, to tell the peer that we want an
1564 // acknowledgement with (at least) that interval.
1565 rt->max_sent_unacked = AV_RB32(pkt->data);
1566 if (rt->max_sent_unacked <= 0) {
1567 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1568 rt->max_sent_unacked);
1569 return AVERROR_INVALIDDATA;
1572 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1577 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
1579 RTMPContext *rt = s->priv_data;
1581 if (pkt->size < 4) {
1582 av_log(s, AV_LOG_ERROR,
1583 "Too short window acknowledgement size packet (%d)\n",
1585 return AVERROR_INVALIDDATA;
1588 rt->receive_report_size = AV_RB32(pkt->data);
1589 if (rt->receive_report_size <= 0) {
1590 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1591 rt->receive_report_size);
1592 return AVERROR_INVALIDDATA;
1594 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1595 // Send an Acknowledgement packet after receiving half the maximum
1596 // size, to make sure the peer can keep on sending without waiting
1597 // for acknowledgements.
1598 rt->receive_report_size >>= 1;
1603 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1604 const char *opaque, const char *challenge)
1607 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1608 struct AVMD5 *md5 = av_md5_alloc();
1610 return AVERROR(ENOMEM);
1612 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1615 av_md5_update(md5, user, strlen(user));
1616 av_md5_update(md5, salt, strlen(salt));
1617 av_md5_update(md5, rt->password, strlen(rt->password));
1618 av_md5_final(md5, hash);
1619 av_base64_encode(hashstr, sizeof(hashstr), hash,
1622 av_md5_update(md5, hashstr, strlen(hashstr));
1624 av_md5_update(md5, opaque, strlen(opaque));
1626 av_md5_update(md5, challenge, strlen(challenge));
1627 av_md5_update(md5, challenge2, strlen(challenge2));
1628 av_md5_final(md5, hash);
1629 av_base64_encode(hashstr, sizeof(hashstr), hash,
1631 snprintf(rt->auth_params, sizeof(rt->auth_params),
1632 "?authmod=%s&user=%s&challenge=%s&response=%s",
1633 "adobe", user, challenge2, hashstr);
1635 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1636 "&opaque=%s", opaque);
1642 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1645 char hashstr1[33], hashstr2[33];
1646 const char *realm = "live";
1647 const char *method = "publish";
1648 const char *qop = "auth";
1649 const char *nc = "00000001";
1651 struct AVMD5 *md5 = av_md5_alloc();
1653 return AVERROR(ENOMEM);
1655 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1658 av_md5_update(md5, user, strlen(user));
1659 av_md5_update(md5, ":", 1);
1660 av_md5_update(md5, realm, strlen(realm));
1661 av_md5_update(md5, ":", 1);
1662 av_md5_update(md5, rt->password, strlen(rt->password));
1663 av_md5_final(md5, hash);
1664 ff_data_to_hex(hashstr1, hash, 16, 1);
1665 hashstr1[32] = '\0';
1668 av_md5_update(md5, method, strlen(method));
1669 av_md5_update(md5, ":/", 2);
1670 av_md5_update(md5, rt->app, strlen(rt->app));
1671 if (!strchr(rt->app, '/'))
1672 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1673 av_md5_final(md5, hash);
1674 ff_data_to_hex(hashstr2, hash, 16, 1);
1675 hashstr2[32] = '\0';
1678 av_md5_update(md5, hashstr1, strlen(hashstr1));
1679 av_md5_update(md5, ":", 1);
1681 av_md5_update(md5, nonce, strlen(nonce));
1682 av_md5_update(md5, ":", 1);
1683 av_md5_update(md5, nc, strlen(nc));
1684 av_md5_update(md5, ":", 1);
1685 av_md5_update(md5, cnonce, strlen(cnonce));
1686 av_md5_update(md5, ":", 1);
1687 av_md5_update(md5, qop, strlen(qop));
1688 av_md5_update(md5, ":", 1);
1689 av_md5_update(md5, hashstr2, strlen(hashstr2));
1690 av_md5_final(md5, hash);
1691 ff_data_to_hex(hashstr1, hash, 16, 1);
1693 snprintf(rt->auth_params, sizeof(rt->auth_params),
1694 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1695 "llnw", user, nonce, cnonce, nc, hashstr1);
1701 static int handle_connect_error(URLContext *s, const char *desc)
1703 RTMPContext *rt = s->priv_data;
1704 char buf[300], *ptr, authmod[15];
1706 const char *user = "", *salt = "", *opaque = NULL,
1707 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1709 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1710 !(cptr = strstr(desc, "authmod=llnw"))) {
1711 av_log(s, AV_LOG_ERROR,
1712 "Unknown connect error (unsupported authentication method?)\n");
1713 return AVERROR_UNKNOWN;
1715 cptr += strlen("authmod=");
1716 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1717 authmod[i++] = *cptr++;
1720 if (!rt->username[0] || !rt->password[0]) {
1721 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1722 return AVERROR_UNKNOWN;
1725 if (strstr(desc, "?reason=authfailed")) {
1726 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1727 return AVERROR_UNKNOWN;
1728 } else if (strstr(desc, "?reason=nosuchuser")) {
1729 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1730 return AVERROR_UNKNOWN;
1733 if (rt->auth_tried) {
1734 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1735 return AVERROR_UNKNOWN;
1738 rt->auth_params[0] = '\0';
1740 if (strstr(desc, "code=403 need auth")) {
1741 snprintf(rt->auth_params, sizeof(rt->auth_params),
1742 "?authmod=%s&user=%s", authmod, rt->username);
1746 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1747 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1748 return AVERROR_UNKNOWN;
1751 av_strlcpy(buf, cptr + 1, sizeof(buf));
1755 char *next = strchr(ptr, '&');
1756 char *value = strchr(ptr, '=');
1761 if (!strcmp(ptr, "user")) {
1763 } else if (!strcmp(ptr, "salt")) {
1765 } else if (!strcmp(ptr, "opaque")) {
1767 } else if (!strcmp(ptr, "challenge")) {
1769 } else if (!strcmp(ptr, "nonce")) {
1772 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1775 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1780 if (!strcmp(authmod, "adobe")) {
1781 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1784 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1792 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1794 RTMPContext *rt = s->priv_data;
1795 const uint8_t *data_end = pkt->data + pkt->size;
1796 char *tracked_method = NULL;
1797 int level = AV_LOG_ERROR;
1798 uint8_t tmpstr[256];
1801 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1804 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1805 "description", tmpstr, sizeof(tmpstr))) {
1806 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1807 !strcmp(tracked_method, "releaseStream") ||
1808 !strcmp(tracked_method, "FCSubscribe") ||
1809 !strcmp(tracked_method, "FCPublish"))) {
1810 /* Gracefully ignore Adobe-specific historical artifact errors. */
1811 level = AV_LOG_WARNING;
1813 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1814 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1816 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1817 ret = handle_connect_error(s, tmpstr);
1819 rt->do_reconnect = 1;
1820 level = AV_LOG_VERBOSE;
1823 ret = AVERROR_UNKNOWN;
1824 av_log(s, level, "Server error: %s\n", tmpstr);
1827 av_free(tracked_method);
1831 static int write_begin(URLContext *s)
1833 RTMPContext *rt = s->priv_data;
1835 RTMPPacket spkt = { 0 };
1838 // Send Stream Begin 1
1839 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1840 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1841 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1845 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1846 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1847 bytestream2_put_be32(&pbc, rt->nb_streamid);
1849 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1850 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1852 ff_rtmp_packet_destroy(&spkt);
1857 static int write_status(URLContext *s, RTMPPacket *pkt,
1858 const char *status, const char *filename)
1860 RTMPContext *rt = s->priv_data;
1861 RTMPPacket spkt = { 0 };
1862 char statusmsg[128];
1866 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1868 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1869 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1874 spkt.extra = pkt->extra;
1875 ff_amf_write_string(&pp, "onStatus");
1876 ff_amf_write_number(&pp, 0);
1877 ff_amf_write_null(&pp);
1879 ff_amf_write_object_start(&pp);
1880 ff_amf_write_field_name(&pp, "level");
1881 ff_amf_write_string(&pp, "status");
1882 ff_amf_write_field_name(&pp, "code");
1883 ff_amf_write_string(&pp, status);
1884 ff_amf_write_field_name(&pp, "description");
1885 snprintf(statusmsg, sizeof(statusmsg),
1886 "%s is now published", filename);
1887 ff_amf_write_string(&pp, statusmsg);
1888 ff_amf_write_field_name(&pp, "details");
1889 ff_amf_write_string(&pp, filename);
1890 ff_amf_write_object_end(&pp);
1892 spkt.size = pp - spkt.data;
1893 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1894 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1895 ff_rtmp_packet_destroy(&spkt);
1900 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1902 RTMPContext *rt = s->priv_data;
1908 const uint8_t *p = pkt->data;
1910 RTMPPacket spkt = { 0 };
1914 bytestream2_init(&gbc, p, pkt->size);
1915 if (ff_amf_read_string(&gbc, command, sizeof(command),
1917 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1918 return AVERROR_INVALIDDATA;
1921 ret = ff_amf_read_number(&gbc, &seqnum);
1924 ret = ff_amf_read_null(&gbc);
1927 if (!strcmp(command, "FCPublish") ||
1928 !strcmp(command, "publish")) {
1929 ret = ff_amf_read_string(&gbc, filename,
1930 sizeof(filename), &stringlen);
1932 if (ret == AVERROR(EINVAL))
1933 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1935 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1940 pchar = strrchr(s->filename, '/');
1942 av_log(s, AV_LOG_WARNING,
1943 "Unable to find / in url %s, bad format\n",
1945 pchar = s->filename;
1948 if (strcmp(pchar, filename))
1949 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1950 " %s\n", filename, pchar);
1952 rt->state = STATE_RECEIVING;
1955 if (!strcmp(command, "FCPublish")) {
1956 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1958 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1959 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1963 ff_amf_write_string(&pp, "onFCPublish");
1964 } else if (!strcmp(command, "publish")) {
1965 ret = write_begin(s);
1969 // Send onStatus(NetStream.Publish.Start)
1970 return write_status(s, pkt, "NetStream.Publish.Start",
1972 } else if (!strcmp(command, "play")) {
1973 ret = write_begin(s);
1976 rt->state = STATE_SENDING;
1977 return write_status(s, pkt, "NetStream.Play.Start",
1980 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1982 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1983 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1987 ff_amf_write_string(&pp, "_result");
1988 ff_amf_write_number(&pp, seqnum);
1989 ff_amf_write_null(&pp);
1990 if (!strcmp(command, "createStream")) {
1992 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1993 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1994 ff_amf_write_number(&pp, rt->nb_streamid);
1995 /* By now we don't control which streams are removed in
1996 * deleteStream. There is no stream creation control
1997 * if a client creates more than 2^32 - 2 streams. */
2000 spkt.size = pp - spkt.data;
2001 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2002 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2003 ff_rtmp_packet_destroy(&spkt);
2008 * Read the AMF_NUMBER response ("_result") to a function call
2009 * (e.g. createStream()). This response should be made up of the AMF_STRING
2010 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2011 * successful response, we will return set the value to number (otherwise number
2012 * will not be changed).
2014 * @return 0 if reading the value succeeds, negative value otherwise
2016 static int read_number_result(RTMPPacket *pkt, double *number)
2018 // We only need to fit "_result" in this.
2019 uint8_t strbuffer[8];
2024 bytestream2_init(&gbc, pkt->data, pkt->size);
2026 // Value 1/4: "_result" as AMF_STRING
2027 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2028 return AVERROR_INVALIDDATA;
2029 if (strcmp(strbuffer, "_result"))
2030 return AVERROR_INVALIDDATA;
2031 // Value 2/4: The callee reference number
2032 if (ff_amf_read_number(&gbc, &numbuffer))
2033 return AVERROR_INVALIDDATA;
2035 if (ff_amf_read_null(&gbc))
2036 return AVERROR_INVALIDDATA;
2037 // Value 4/4: The response as AMF_NUMBER
2038 if (ff_amf_read_number(&gbc, &numbuffer))
2039 return AVERROR_INVALIDDATA;
2041 *number = numbuffer;
2046 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2048 RTMPContext *rt = s->priv_data;
2049 char *tracked_method = NULL;
2052 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2055 if (!tracked_method) {
2056 /* Ignore this reply when the current method is not tracked. */
2060 if (!strcmp(tracked_method, "connect")) {
2061 if (!rt->is_input) {
2062 if ((ret = gen_release_stream(s, rt)) < 0)
2065 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2068 if ((ret = gen_window_ack_size(s, rt)) < 0)
2072 if ((ret = gen_create_stream(s, rt)) < 0)
2076 /* Send the FCSubscribe command when the name of live
2077 * stream is defined by the user or if it's a live stream. */
2078 if (rt->subscribe) {
2079 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2081 } else if (rt->live == -1) {
2082 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2086 } else if (!strcmp(tracked_method, "createStream")) {
2088 if (read_number_result(pkt, &stream_id)) {
2089 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2091 rt->stream_id = stream_id;
2094 if (!rt->is_input) {
2095 if ((ret = gen_publish(s, rt)) < 0)
2098 if (rt->live != -1) {
2099 if ((ret = gen_get_stream_length(s, rt)) < 0)
2102 if ((ret = gen_play(s, rt)) < 0)
2104 if ((ret = gen_buffer_time(s, rt)) < 0)
2107 } else if (!strcmp(tracked_method, "getStreamLength")) {
2108 if (read_number_result(pkt, &rt->duration)) {
2109 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2114 av_free(tracked_method);
2118 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2120 RTMPContext *rt = s->priv_data;
2121 const uint8_t *data_end = pkt->data + pkt->size;
2122 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2123 uint8_t tmpstr[256];
2126 for (i = 0; i < 2; i++) {
2127 t = ff_amf_tag_size(ptr, data_end);
2133 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2134 if (!t && !strcmp(tmpstr, "error")) {
2135 t = ff_amf_get_field_value(ptr, data_end,
2136 "description", tmpstr, sizeof(tmpstr));
2137 if (t || !tmpstr[0])
2138 t = ff_amf_get_field_value(ptr, data_end, "code",
2139 tmpstr, sizeof(tmpstr));
2141 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2145 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2146 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2147 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2148 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2149 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2150 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2155 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2157 RTMPContext *rt = s->priv_data;
2160 //TODO: check for the messages sent for wrong state?
2161 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2162 if ((ret = handle_invoke_error(s, pkt)) < 0)
2164 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2165 if ((ret = handle_invoke_result(s, pkt)) < 0)
2167 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2168 if ((ret = handle_invoke_status(s, pkt)) < 0)
2170 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2171 if ((ret = gen_check_bw(s, rt)) < 0)
2173 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2174 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2175 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2176 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2177 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2178 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2179 if ((ret = send_invoke_response(s, pkt)) < 0)
2186 static int update_offset(RTMPContext *rt, int size)
2190 // generate packet header and put data into buffer for FLV demuxer
2191 if (rt->flv_off < rt->flv_size) {
2192 // There is old unread data in the buffer, thus append at the end
2193 old_flv_size = rt->flv_size;
2194 rt->flv_size += size;
2196 // All data has been read, write the new data at the start of the buffer
2198 rt->flv_size = size;
2202 return old_flv_size;
2205 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2207 int old_flv_size, ret;
2209 const uint8_t *data = pkt->data + skip;
2210 const int size = pkt->size - skip;
2211 uint32_t ts = pkt->timestamp;
2213 if (pkt->type == RTMP_PT_AUDIO) {
2215 } else if (pkt->type == RTMP_PT_VIDEO) {
2219 old_flv_size = update_offset(rt, size + 15);
2221 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2222 rt->flv_size = rt->flv_off = 0;
2225 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2226 bytestream2_skip_p(&pbc, old_flv_size);
2227 bytestream2_put_byte(&pbc, pkt->type);
2228 bytestream2_put_be24(&pbc, size);
2229 bytestream2_put_be24(&pbc, ts);
2230 bytestream2_put_byte(&pbc, ts >> 24);
2231 bytestream2_put_be24(&pbc, 0);
2232 bytestream2_put_buffer(&pbc, data, size);
2233 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2238 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2240 RTMPContext *rt = s->priv_data;
2241 uint8_t commandbuffer[64];
2242 char statusmsg[128];
2243 int stringlen, ret, skip = 0;
2246 bytestream2_init(&gbc, pkt->data, pkt->size);
2247 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2249 return AVERROR_INVALIDDATA;
2251 if (!strcmp(commandbuffer, "onMetaData")) {
2252 // metadata properties should be stored in a mixed array
2253 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2254 // We have found a metaData Array so flv can determine the streams
2256 rt->received_metadata = 1;
2257 // skip 32-bit max array index
2258 bytestream2_skip(&gbc, 4);
2259 while (bytestream2_get_bytes_left(&gbc) > 3) {
2260 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2262 return AVERROR_INVALIDDATA;
2263 // We do not care about the content of the property (yet).
2264 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2266 return AVERROR_INVALIDDATA;
2267 bytestream2_skip(&gbc, stringlen);
2269 // The presence of the following properties indicates that the
2270 // respective streams are present.
2271 if (!strcmp(statusmsg, "videocodecid")) {
2274 if (!strcmp(statusmsg, "audiocodecid")) {
2278 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2279 return AVERROR_INVALIDDATA;
2283 // Skip the @setDataFrame string and validate it is a notification
2284 if (!strcmp(commandbuffer, "@setDataFrame")) {
2285 skip = gbc.buffer - pkt->data;
2286 ret = ff_amf_read_string(&gbc, statusmsg,
2287 sizeof(statusmsg), &stringlen);
2289 return AVERROR_INVALIDDATA;
2292 return append_flv_data(rt, pkt, skip);
2296 * Parse received packet and possibly perform some action depending on
2297 * the packet contents.
2298 * @return 0 for no errors, negative values for serious errors which prevent
2299 * further communications, positive values for uncritical errors
2301 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2306 ff_rtmp_packet_dump(s, pkt);
2309 switch (pkt->type) {
2310 case RTMP_PT_BYTES_READ:
2311 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2313 case RTMP_PT_CHUNK_SIZE:
2314 if ((ret = handle_chunk_size(s, pkt)) < 0)
2317 case RTMP_PT_USER_CONTROL:
2318 if ((ret = handle_user_control(s, pkt)) < 0)
2321 case RTMP_PT_SET_PEER_BW:
2322 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2325 case RTMP_PT_WINDOW_ACK_SIZE:
2326 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2329 case RTMP_PT_INVOKE:
2330 if ((ret = handle_invoke(s, pkt)) < 0)
2335 case RTMP_PT_METADATA:
2336 case RTMP_PT_NOTIFY:
2337 /* Audio, Video and Metadata packets are parsed in get_packet() */
2340 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2346 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2348 int ret, old_flv_size, type;
2349 const uint8_t *next;
2352 uint32_t ts, cts, pts = 0;
2354 old_flv_size = update_offset(rt, pkt->size);
2356 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2357 rt->flv_size = rt->flv_off = 0;
2362 p = rt->flv_data + old_flv_size;
2364 /* copy data while rewriting timestamps */
2365 ts = pkt->timestamp;
2367 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2368 type = bytestream_get_byte(&next);
2369 size = bytestream_get_be24(&next);
2370 cts = bytestream_get_be24(&next);
2371 cts |= bytestream_get_byte(&next) << 24;
2376 if (size + 3 + 4 > pkt->data + pkt->size - next)
2378 bytestream_put_byte(&p, type);
2379 bytestream_put_be24(&p, size);
2380 bytestream_put_be24(&p, ts);
2381 bytestream_put_byte(&p, ts >> 24);
2382 memcpy(p, next, size + 3 + 4);
2384 bytestream_put_be32(&p, size + RTMP_HEADER);
2385 next += size + 3 + 4;
2387 if (p != rt->flv_data + rt->flv_size) {
2388 av_log(rt, AV_LOG_WARNING, "Incomplete flv packets in "
2389 "RTMP_PT_METADATA packet\n");
2390 rt->flv_size = p - rt->flv_data;
2397 * Interact with the server by receiving and sending RTMP packets until
2398 * there is some significant data (media data or expected status notification).
2400 * @param s reading context
2401 * @param for_header non-zero value tells function to work until it
2402 * gets notification from the server that playing has been started,
2403 * otherwise function will work until some media data is received (or
2405 * @return 0 for successful operation, negative value in case of error
2407 static int get_packet(URLContext *s, int for_header)
2409 RTMPContext *rt = s->priv_data;
2412 if (rt->state == STATE_STOPPED)
2416 RTMPPacket rpkt = { 0 };
2417 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2418 rt->in_chunk_size, &rt->prev_pkt[0],
2419 &rt->nb_prev_pkt[0])) <= 0) {
2421 return AVERROR(EAGAIN);
2423 return AVERROR(EIO);
2427 // Track timestamp for later use
2428 rt->last_timestamp = rpkt.timestamp;
2430 rt->bytes_read += ret;
2431 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2432 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2433 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) {
2434 ff_rtmp_packet_destroy(&rpkt);
2437 rt->last_bytes_read = rt->bytes_read;
2440 ret = rtmp_parse_result(s, rt, &rpkt);
2442 // At this point we must check if we are in the seek state and continue
2443 // with the next packet. handle_invoke will get us out of this state
2444 // when the right message is encountered
2445 if (rt->state == STATE_SEEKING) {
2446 ff_rtmp_packet_destroy(&rpkt);
2447 // We continue, let the natural flow of things happen:
2448 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2452 if (ret < 0) {//serious error in current packet
2453 ff_rtmp_packet_destroy(&rpkt);
2456 if (rt->do_reconnect && for_header) {
2457 ff_rtmp_packet_destroy(&rpkt);
2460 if (rt->state == STATE_STOPPED) {
2461 ff_rtmp_packet_destroy(&rpkt);
2464 if (for_header && (rt->state == STATE_PLAYING ||
2465 rt->state == STATE_PUBLISHING ||
2466 rt->state == STATE_SENDING ||
2467 rt->state == STATE_RECEIVING)) {
2468 ff_rtmp_packet_destroy(&rpkt);
2471 if (!rpkt.size || !rt->is_input) {
2472 ff_rtmp_packet_destroy(&rpkt);
2475 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2476 ret = append_flv_data(rt, &rpkt, 0);
2477 ff_rtmp_packet_destroy(&rpkt);
2479 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2480 ret = handle_notify(s, &rpkt);
2481 ff_rtmp_packet_destroy(&rpkt);
2483 } else if (rpkt.type == RTMP_PT_METADATA) {
2484 ret = handle_metadata(rt, &rpkt);
2485 ff_rtmp_packet_destroy(&rpkt);
2488 ff_rtmp_packet_destroy(&rpkt);
2492 static int rtmp_close(URLContext *h)
2494 RTMPContext *rt = h->priv_data;
2497 if (!rt->is_input) {
2498 rt->flv_data = NULL;
2499 if (rt->out_pkt.size)
2500 ff_rtmp_packet_destroy(&rt->out_pkt);
2501 if (rt->state > STATE_FCPUBLISH)
2502 ret = gen_fcunpublish_stream(h, rt);
2504 if (rt->state > STATE_HANDSHAKED)
2505 ret = gen_delete_stream(h, rt);
2506 for (i = 0; i < 2; i++) {
2507 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2508 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2509 av_freep(&rt->prev_pkt[i]);
2512 free_tracked_methods(rt);
2513 av_freep(&rt->flv_data);
2514 ffurl_closep(&rt->stream);
2519 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2520 * demuxer about the duration of the stream.
2522 * This should only be done if there was no real onMetadata packet sent by the
2523 * server at the start of the stream and if we were able to retrieve a valid
2524 * duration via a getStreamLength call.
2526 * @return 0 for successful operation, negative value in case of error
2528 static int inject_fake_duration_metadata(RTMPContext *rt)
2530 // We need to insert the metadata packet directly after the FLV
2531 // header, i.e. we need to move all other already read data by the
2532 // size of our fake metadata packet.
2535 // Keep old flv_data pointer
2536 uint8_t* old_flv_data = rt->flv_data;
2537 // Allocate a new flv_data pointer with enough space for the additional package
2538 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2539 rt->flv_data = old_flv_data;
2540 return AVERROR(ENOMEM);
2544 memcpy(rt->flv_data, old_flv_data, 13);
2545 // Copy remaining packets
2546 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2547 // Increase the size by the injected packet
2549 // Delete the old FLV data
2550 av_freep(&old_flv_data);
2552 p = rt->flv_data + 13;
2553 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2554 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2555 bytestream_put_be24(&p, 0); // timestamp
2556 bytestream_put_be32(&p, 0); // reserved
2558 // first event name as a string
2559 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2560 // "onMetaData" as AMF string
2561 bytestream_put_be16(&p, 10);
2562 bytestream_put_buffer(&p, "onMetaData", 10);
2564 // mixed array (hash) with size and string/type/data tuples
2565 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2566 bytestream_put_be32(&p, 1); // metadata_count
2568 // "duration" as AMF string
2569 bytestream_put_be16(&p, 8);
2570 bytestream_put_buffer(&p, "duration", 8);
2571 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2572 bytestream_put_be64(&p, av_double2int(rt->duration));
2575 bytestream_put_be16(&p, 0); // Empty string
2576 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2577 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2583 * Open RTMP connection and verify that the stream can be played.
2585 * URL syntax: rtmp://server[:port][/app][/playpath]
2586 * where 'app' is first one or two directories in the path
2587 * (e.g. /ondemand/, /flash/live/, etc.)
2588 * and 'playpath' is a file name (the rest of the path,
2589 * may be prefixed with "mp4:")
2591 static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2593 RTMPContext *rt = s->priv_data;
2594 char proto[8], hostname[256], path[1024], auth[100], *fname;
2595 char *old_app, *qmark, *n, fname_buffer[1024];
2600 if (rt->listen_timeout > 0)
2603 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2605 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2606 hostname, sizeof(hostname), &port,
2607 path, sizeof(path), s->filename);
2609 n = strchr(path, ' ');
2611 av_log(s, AV_LOG_WARNING,
2612 "Detected librtmp style URL parameters, these aren't supported "
2613 "by the libavformat internal RTMP handler currently enabled. "
2614 "See the documentation for the correct way to pass parameters.\n");
2615 *n = '\0'; // Trim not supported part
2619 char *ptr = strchr(auth, ':');
2622 av_strlcpy(rt->username, auth, sizeof(rt->username));
2623 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2627 if (rt->listen && strcmp(proto, "rtmp")) {
2628 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2630 return AVERROR(EINVAL);
2632 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2633 if (!strcmp(proto, "rtmpts"))
2634 av_dict_set(opts, "ffrtmphttp_tls", "1", 1);
2636 /* open the http tunneling connection */
2637 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2638 } else if (!strcmp(proto, "rtmps")) {
2639 /* open the tls connection */
2641 port = RTMPS_DEFAULT_PORT;
2642 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2643 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2644 if (!strcmp(proto, "rtmpte"))
2645 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2647 /* open the encrypted connection */
2648 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2651 /* open the tcp connection */
2653 port = RTMP_DEFAULT_PORT;
2655 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2656 "?listen&listen_timeout=%d",
2657 rt->listen_timeout * 1000);
2659 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2663 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2664 &s->interrupt_callback, opts,
2665 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2666 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2670 if (rt->swfverify) {
2671 if ((ret = rtmp_calc_swfhash(s)) < 0)
2675 rt->state = STATE_START;
2676 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2678 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2681 rt->out_chunk_size = 128;
2682 rt->in_chunk_size = 128; // Probably overwritten later
2683 rt->state = STATE_HANDSHAKED;
2685 // Keep the application name when it has been defined by the user.
2688 rt->app = av_malloc(APP_MAX_LENGTH);
2690 ret = AVERROR(ENOMEM);
2694 //extract "app" part from path
2695 qmark = strchr(path, '?');
2696 if (qmark && strstr(qmark, "slist=")) {
2698 // After slist we have the playpath, the full path is used as app
2699 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2700 fname = strstr(path, "slist=") + 6;
2701 // Strip any further query parameters from fname
2702 amp = strchr(fname, '&');
2704 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2705 sizeof(fname_buffer)));
2706 fname = fname_buffer;
2708 } else if (!strncmp(path, "/ondemand/", 10)) {
2710 memcpy(rt->app, "ondemand", 9);
2712 char *next = *path ? path + 1 : path;
2713 char *p = strchr(next, '/');
2716 // If name of application has been defined by the user, assume that
2717 // playpath is provided in the URL
2721 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2724 // make sure we do not mismatch a playpath for an application instance
2725 char *c = strchr(p + 1, ':');
2726 fname = strchr(p + 1, '/');
2727 if (!fname || (c && c < fname)) {
2729 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2732 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2738 // The name of application has been defined by the user, override it.
2739 if (strlen(old_app) >= APP_MAX_LENGTH) {
2740 ret = AVERROR(EINVAL);
2747 if (!rt->playpath) {
2750 max_len = strlen(fname) + 5; // add prefix "mp4:"
2751 rt->playpath = av_malloc(max_len);
2752 if (!rt->playpath) {
2753 ret = AVERROR(ENOMEM);
2758 int len = strlen(fname);
2759 if (!strchr(fname, ':') && len >= 4 &&
2760 (!strcmp(fname + len - 4, ".f4v") ||
2761 !strcmp(fname + len - 4, ".mp4"))) {
2762 memcpy(rt->playpath, "mp4:", 5);
2764 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2765 fname[len - 4] = '\0';
2766 rt->playpath[0] = 0;
2768 av_strlcat(rt->playpath, fname, max_len);
2770 rt->playpath[0] = '\0';
2775 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2777 ret = AVERROR(ENOMEM);
2780 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2781 port, "/%s", rt->app);
2784 if (!rt->flashver) {
2785 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2786 if (!rt->flashver) {
2787 ret = AVERROR(ENOMEM);
2791 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2792 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2793 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2795 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2796 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2800 rt->receive_report_size = 1048576;
2804 rt->received_metadata = 0;
2805 rt->last_bytes_read = 0;
2806 rt->max_sent_unacked = 2500000;
2809 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2810 proto, path, rt->app, rt->playpath);
2812 if ((ret = gen_connect(s, rt)) < 0)
2815 if ((ret = read_connect(s, s->priv_data)) < 0)
2820 ret = get_packet(s, 1);
2821 } while (ret == AVERROR(EAGAIN));
2825 if (rt->do_reconnect) {
2827 ffurl_closep(&rt->stream);
2828 rt->do_reconnect = 0;
2830 for (i = 0; i < 2; i++)
2831 memset(rt->prev_pkt[i], 0,
2832 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2833 free_tracked_methods(rt);
2838 // generate FLV header for demuxer
2840 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2843 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2845 // Read packets until we reach the first A/V packet or read metadata.
2846 // If there was a metadata package in front of the A/V packets, we can
2847 // build the FLV header from this. If we do not receive any metadata,
2848 // the FLV decoder will allocate the needed streams when their first
2849 // audio or video packet arrives.
2850 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2851 if ((ret = get_packet(s, 0)) < 0)
2855 // Either after we have read the metadata or (if there is none) the
2856 // first packet of an A/V stream, we have a better knowledge about the
2857 // streams, so set the FLV header accordingly.
2858 if (rt->has_audio) {
2859 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2861 if (rt->has_video) {
2862 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2865 // If we received the first packet of an A/V stream and no metadata but
2866 // the server returned a valid duration, create a fake metadata packet
2867 // to inform the FLV decoder about the duration.
2868 if (!rt->received_metadata && rt->duration > 0) {
2869 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2874 rt->flv_data = NULL;
2876 rt->skip_bytes = 13;
2879 s->max_packet_size = rt->stream->max_packet_size;
2884 av_freep(&rt->playpath);
2885 av_freep(&rt->tcurl);
2886 av_freep(&rt->flashver);
2892 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2894 RTMPContext *rt = s->priv_data;
2895 int orig_size = size;
2899 int data_left = rt->flv_size - rt->flv_off;
2901 if (data_left >= size) {
2902 memcpy(buf, rt->flv_data + rt->flv_off, size);
2903 rt->flv_off += size;
2906 if (data_left > 0) {
2907 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2910 rt->flv_off = rt->flv_size;
2913 if ((ret = get_packet(s, 0)) < 0)
2919 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2922 RTMPContext *rt = s->priv_data;
2924 av_log(s, AV_LOG_DEBUG,
2925 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2926 stream_index, timestamp, flags);
2927 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2928 av_log(s, AV_LOG_ERROR,
2929 "Unable to send seek command on stream index %d at timestamp "
2930 "%"PRId64" with flags %08x\n",
2931 stream_index, timestamp, flags);
2934 rt->flv_off = rt->flv_size;
2935 rt->state = STATE_SEEKING;
2939 static int rtmp_pause(URLContext *s, int pause)
2941 RTMPContext *rt = s->priv_data;
2943 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2944 rt->last_timestamp);
2945 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2946 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2947 rt->last_timestamp);
2953 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2955 RTMPContext *rt = s->priv_data;
2956 int size_temp = size;
2957 int pktsize, pkttype, copy;
2959 const uint8_t *buf_temp = buf;
2964 if (rt->skip_bytes) {
2965 int skip = FFMIN(rt->skip_bytes, size_temp);
2968 rt->skip_bytes -= skip;
2972 if (rt->flv_header_bytes < RTMP_HEADER) {
2973 const uint8_t *header = rt->flv_header;
2974 int channel = RTMP_AUDIO_CHANNEL;
2976 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2977 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2978 rt->flv_header_bytes += copy;
2980 if (rt->flv_header_bytes < RTMP_HEADER)
2983 pkttype = bytestream_get_byte(&header);
2984 pktsize = bytestream_get_be24(&header);
2985 ts = bytestream_get_be24(&header);
2986 ts |= bytestream_get_byte(&header) << 24;
2987 bytestream_get_be24(&header);
2988 rt->flv_size = pktsize;
2990 if (pkttype == RTMP_PT_VIDEO)
2991 channel = RTMP_VIDEO_CHANNEL;
2993 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2994 pkttype == RTMP_PT_NOTIFY) {
2995 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2996 &rt->nb_prev_pkt[1],
2999 // Force sending a full 12 bytes header by clearing the
3000 // channel id, to make it not match a potential earlier
3001 // packet in the same channel.
3002 rt->prev_pkt[1][channel].channel_id = 0;
3005 //this can be a big packet, it's better to send it right here
3006 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3007 pkttype, ts, pktsize)) < 0)
3010 rt->out_pkt.extra = rt->stream_id;
3011 rt->flv_data = rt->out_pkt.data;
3014 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3015 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3016 rt->flv_off += copy;
3019 if (rt->flv_off == rt->flv_size) {
3022 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3023 // For onMetaData and |RtmpSampleAccess packets, we want
3024 // @setDataFrame prepended to the packet before it gets sent.
3025 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3027 uint8_t commandbuffer[64];
3031 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3032 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3034 if (!strcmp(commandbuffer, "onMetaData") ||
3035 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3037 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3038 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3041 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3042 rt->out_pkt.size += 16;
3043 ptr = rt->out_pkt.data;
3044 ff_amf_write_string(&ptr, "@setDataFrame");
3049 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3053 rt->flv_header_bytes = 0;
3054 rt->flv_nb_packets++;
3056 } while (buf_temp - buf < size);
3058 if (rt->flv_nb_packets < rt->flush_interval)
3060 rt->flv_nb_packets = 0;
3062 /* set stream into nonblocking mode */
3063 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3065 /* try to read one byte from the stream */
3066 ret = ffurl_read(rt->stream, &c, 1);
3068 /* switch the stream back into blocking mode */
3069 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3071 if (ret == AVERROR(EAGAIN)) {
3072 /* no incoming data to handle */
3074 } else if (ret < 0) {
3076 } else if (ret == 1) {
3077 RTMPPacket rpkt = { 0 };
3079 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3082 &rt->nb_prev_pkt[0], c)) <= 0)
3085 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3088 ff_rtmp_packet_destroy(&rpkt);
3094 #define OFFSET(x) offsetof(RTMPContext, x)
3095 #define DEC AV_OPT_FLAG_DECODING_PARAM
3096 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3098 static const AVOption rtmp_options[] = {
3099 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3100 {"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},
3101 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3102 {"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},
3103 {"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},
3104 {"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"},
3105 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3106 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3107 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3108 {"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},
3109 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3110 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3111 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3112 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3113 {"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},
3114 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3115 {"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},
3116 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3117 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3118 {"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" },
3122 #define RTMP_PROTOCOL(flavor) \
3123 static const AVClass flavor##_class = { \
3124 .class_name = #flavor, \
3125 .item_name = av_default_item_name, \
3126 .option = rtmp_options, \
3127 .version = LIBAVUTIL_VERSION_INT, \
3130 const URLProtocol ff_##flavor##_protocol = { \
3132 .url_open2 = rtmp_open, \
3133 .url_read = rtmp_read, \
3134 .url_read_seek = rtmp_seek, \
3135 .url_read_pause = rtmp_pause, \
3136 .url_write = rtmp_write, \
3137 .url_close = rtmp_close, \
3138 .priv_data_size = sizeof(RTMPContext), \
3139 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3140 .priv_data_class= &flavor##_class, \
3145 RTMP_PROTOCOL(rtmpe)
3146 RTMP_PROTOCOL(rtmps)
3147 RTMP_PROTOCOL(rtmpt)
3148 RTMP_PROTOCOL(rtmpte)
3149 RTMP_PROTOCOL(rtmpts)