2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/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 128
51 #define PLAYPATH_MAX_LENGTH 256
52 #define TCURL_MAX_LENGTH 512
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 uint32_t bytes_read; ///< number of bytes read from server
97 uint32_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);
159 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
163 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
164 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
165 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
166 sizeof(*rt->tracked_methods))) < 0) {
167 rt->nb_tracked_methods = 0;
168 rt->tracked_methods_size = 0;
173 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
174 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
175 return AVERROR(ENOMEM);
176 rt->tracked_methods[rt->nb_tracked_methods].id = id;
177 rt->nb_tracked_methods++;
182 static void del_tracked_method(RTMPContext *rt, int index)
184 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
185 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
186 rt->nb_tracked_methods--;
189 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
190 char **tracked_method)
192 RTMPContext *rt = s->priv_data;
198 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
199 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
202 for (i = 0; i < rt->nb_tracked_methods; i++) {
203 if (rt->tracked_methods[i].id != pkt_id)
206 *tracked_method = rt->tracked_methods[i].name;
207 del_tracked_method(rt, i);
214 static void free_tracked_methods(RTMPContext *rt)
218 for (i = 0; i < rt->nb_tracked_methods; i ++)
219 av_free(rt->tracked_methods[i].name);
220 av_free(rt->tracked_methods);
221 rt->tracked_methods = NULL;
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,
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);
405 static int read_connect(URLContext *s, RTMPContext *rt)
407 RTMPPacket pkt = { 0 };
417 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
418 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
421 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
422 if ((ret = handle_chunk_size(s, &pkt)) < 0)
424 ff_rtmp_packet_destroy(&pkt);
425 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
426 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
431 bytestream2_init(&gbc, cp, pkt.size);
432 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
433 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
434 ff_rtmp_packet_destroy(&pkt);
435 return AVERROR_INVALIDDATA;
437 if (strcmp(command, "connect")) {
438 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
439 ff_rtmp_packet_destroy(&pkt);
440 return AVERROR_INVALIDDATA;
442 ret = ff_amf_read_number(&gbc, &seqnum);
444 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
445 /* Here one could parse an AMF Object with data as flashVers and others. */
446 ret = ff_amf_get_field_value(gbc.buffer,
447 gbc.buffer + bytestream2_get_bytes_left(&gbc),
448 "app", tmpstr, sizeof(tmpstr));
450 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
451 if (!ret && strcmp(tmpstr, rt->app))
452 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
454 ff_rtmp_packet_destroy(&pkt);
456 // Send Window Acknowledgement Size (as defined in specification)
457 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
458 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
461 // Inform the peer about how often we want acknowledgements about what
462 // we send. (We don't check for the acknowledgements currently.)
463 bytestream_put_be32(&p, rt->max_sent_unacked);
464 pkt.size = p - pkt.data;
465 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
466 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
467 ff_rtmp_packet_destroy(&pkt);
470 // Set Peer Bandwidth
471 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
472 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
475 // Tell the peer to only send this many bytes unless it gets acknowledgements.
476 // This could be any arbitrary value we want here.
477 bytestream_put_be32(&p, rt->max_sent_unacked);
478 bytestream_put_byte(&p, 2); // dynamic
479 pkt.size = p - pkt.data;
480 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
481 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
482 ff_rtmp_packet_destroy(&pkt);
487 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
488 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
492 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
493 bytestream_put_be32(&p, 0); // Stream 0
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);
501 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
502 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
506 bytestream_put_be32(&p, rt->out_chunk_size);
507 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
508 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
509 ff_rtmp_packet_destroy(&pkt);
513 // Send _result NetConnection.Connect.Success to connect
514 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
516 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
520 ff_amf_write_string(&p, "_result");
521 ff_amf_write_number(&p, seqnum);
523 ff_amf_write_object_start(&p);
524 ff_amf_write_field_name(&p, "fmsVer");
525 ff_amf_write_string(&p, "FMS/3,0,1,123");
526 ff_amf_write_field_name(&p, "capabilities");
527 ff_amf_write_number(&p, 31);
528 ff_amf_write_object_end(&p);
530 ff_amf_write_object_start(&p);
531 ff_amf_write_field_name(&p, "level");
532 ff_amf_write_string(&p, "status");
533 ff_amf_write_field_name(&p, "code");
534 ff_amf_write_string(&p, "NetConnection.Connect.Success");
535 ff_amf_write_field_name(&p, "description");
536 ff_amf_write_string(&p, "Connection succeeded.");
537 ff_amf_write_field_name(&p, "objectEncoding");
538 ff_amf_write_number(&p, 0);
539 ff_amf_write_object_end(&p);
541 pkt.size = p - pkt.data;
542 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
543 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
544 ff_rtmp_packet_destroy(&pkt);
548 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
549 RTMP_PT_INVOKE, 0, 30)) < 0)
552 ff_amf_write_string(&p, "onBWDone");
553 ff_amf_write_number(&p, 0);
554 ff_amf_write_null(&p);
555 ff_amf_write_number(&p, 8192);
556 pkt.size = p - pkt.data;
557 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
558 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
559 ff_rtmp_packet_destroy(&pkt);
565 * Generate 'releaseStream' call and send it to the server. It should make
566 * the server release some channel for media streams.
568 static int gen_release_stream(URLContext *s, RTMPContext *rt)
574 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
575 0, 29 + strlen(rt->playpath))) < 0)
578 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
580 ff_amf_write_string(&p, "releaseStream");
581 ff_amf_write_number(&p, ++rt->nb_invokes);
582 ff_amf_write_null(&p);
583 ff_amf_write_string(&p, rt->playpath);
585 return rtmp_send_packet(rt, &pkt, 1);
589 * Generate 'FCPublish' call and send it to the server. It should make
590 * the server prepare for receiving media streams.
592 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
598 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
599 0, 25 + strlen(rt->playpath))) < 0)
602 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
604 ff_amf_write_string(&p, "FCPublish");
605 ff_amf_write_number(&p, ++rt->nb_invokes);
606 ff_amf_write_null(&p);
607 ff_amf_write_string(&p, rt->playpath);
609 return rtmp_send_packet(rt, &pkt, 1);
613 * Generate 'FCUnpublish' call and send it to the server. It should make
614 * the server destroy stream.
616 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
622 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
623 0, 27 + strlen(rt->playpath))) < 0)
626 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
628 ff_amf_write_string(&p, "FCUnpublish");
629 ff_amf_write_number(&p, ++rt->nb_invokes);
630 ff_amf_write_null(&p);
631 ff_amf_write_string(&p, rt->playpath);
633 return rtmp_send_packet(rt, &pkt, 0);
637 * Generate 'createStream' call and send it to the server. It should make
638 * the server allocate some channel for media streams.
640 static int gen_create_stream(URLContext *s, RTMPContext *rt)
646 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
648 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
653 ff_amf_write_string(&p, "createStream");
654 ff_amf_write_number(&p, ++rt->nb_invokes);
655 ff_amf_write_null(&p);
657 return rtmp_send_packet(rt, &pkt, 1);
662 * Generate 'deleteStream' call and send it to the server. It should make
663 * the server remove some channel for media streams.
665 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
671 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
673 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
678 ff_amf_write_string(&p, "deleteStream");
679 ff_amf_write_number(&p, ++rt->nb_invokes);
680 ff_amf_write_null(&p);
681 ff_amf_write_number(&p, rt->stream_id);
683 return rtmp_send_packet(rt, &pkt, 0);
687 * Generate 'getStreamLength' call and send it to the server. If the server
688 * knows the duration of the selected stream, it will reply with the duration
691 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
697 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
698 0, 31 + strlen(rt->playpath))) < 0)
702 ff_amf_write_string(&p, "getStreamLength");
703 ff_amf_write_number(&p, ++rt->nb_invokes);
704 ff_amf_write_null(&p);
705 ff_amf_write_string(&p, rt->playpath);
707 return rtmp_send_packet(rt, &pkt, 1);
711 * Generate client buffer time and send it to the server.
713 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
719 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
724 bytestream_put_be16(&p, 3); // SetBuffer Length
725 bytestream_put_be32(&p, rt->stream_id);
726 bytestream_put_be32(&p, rt->client_buffer_time);
728 return rtmp_send_packet(rt, &pkt, 0);
732 * Generate 'play' call and send it to the server, then ping the server
733 * to start actual playing.
735 static int gen_play(URLContext *s, RTMPContext *rt)
741 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
743 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
744 0, 29 + strlen(rt->playpath))) < 0)
747 pkt.extra = rt->stream_id;
750 ff_amf_write_string(&p, "play");
751 ff_amf_write_number(&p, ++rt->nb_invokes);
752 ff_amf_write_null(&p);
753 ff_amf_write_string(&p, rt->playpath);
754 ff_amf_write_number(&p, rt->live * 1000);
756 return rtmp_send_packet(rt, &pkt, 1);
759 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
765 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
768 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
771 pkt.extra = rt->stream_id;
774 ff_amf_write_string(&p, "seek");
775 ff_amf_write_number(&p, 0); //no tracking back responses
776 ff_amf_write_null(&p); //as usual, the first null param
777 ff_amf_write_number(&p, timestamp); //where we want to jump
779 return rtmp_send_packet(rt, &pkt, 1);
783 * Generate a pause packet that either pauses or unpauses the current stream.
785 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
791 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
794 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
797 pkt.extra = rt->stream_id;
800 ff_amf_write_string(&p, "pause");
801 ff_amf_write_number(&p, 0); //no tracking back responses
802 ff_amf_write_null(&p); //as usual, the first null param
803 ff_amf_write_bool(&p, pause); // pause or unpause
804 ff_amf_write_number(&p, timestamp); //where we pause the stream
806 return rtmp_send_packet(rt, &pkt, 1);
810 * Generate 'publish' call and send it to the server.
812 static int gen_publish(URLContext *s, RTMPContext *rt)
818 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
820 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
821 0, 30 + strlen(rt->playpath))) < 0)
824 pkt.extra = rt->stream_id;
827 ff_amf_write_string(&p, "publish");
828 ff_amf_write_number(&p, ++rt->nb_invokes);
829 ff_amf_write_null(&p);
830 ff_amf_write_string(&p, rt->playpath);
831 ff_amf_write_string(&p, "live");
833 return rtmp_send_packet(rt, &pkt, 1);
837 * Generate ping reply and send it to the server.
839 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
845 if (ppkt->size < 6) {
846 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
848 return AVERROR_INVALIDDATA;
851 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
852 ppkt->timestamp + 1, 6)) < 0)
856 bytestream_put_be16(&p, 7); // PingResponse
857 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
859 return rtmp_send_packet(rt, &pkt, 0);
863 * Generate SWF verification message and send it to the server.
865 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
871 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
872 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
877 bytestream_put_be16(&p, 27);
878 memcpy(p, rt->swfverification, 42);
880 return rtmp_send_packet(rt, &pkt, 0);
884 * Generate window acknowledgement size message and send it to the server.
886 static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
892 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
897 bytestream_put_be32(&p, rt->max_sent_unacked);
899 return rtmp_send_packet(rt, &pkt, 0);
903 * Generate check bandwidth message and send it to the server.
905 static int gen_check_bw(URLContext *s, RTMPContext *rt)
911 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
916 ff_amf_write_string(&p, "_checkbw");
917 ff_amf_write_number(&p, ++rt->nb_invokes);
918 ff_amf_write_null(&p);
920 return rtmp_send_packet(rt, &pkt, 1);
924 * Generate report on bytes read so far and send it to the server.
926 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
932 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
937 bytestream_put_be32(&p, rt->bytes_read);
939 return rtmp_send_packet(rt, &pkt, 0);
942 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
943 const char *subscribe)
949 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
950 0, 27 + strlen(subscribe))) < 0)
954 ff_amf_write_string(&p, "FCSubscribe");
955 ff_amf_write_number(&p, ++rt->nb_invokes);
956 ff_amf_write_null(&p);
957 ff_amf_write_string(&p, subscribe);
959 return rtmp_send_packet(rt, &pkt, 1);
963 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
964 * will be stored) into that packet.
966 * @param buf handshake data (1536 bytes)
967 * @param encrypted use an encrypted connection (RTMPE)
968 * @return offset to the digest inside input data
970 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
975 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
977 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
979 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
980 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
989 * Verify that the received server response has the expected digest value.
991 * @param buf handshake data received from the server (1536 bytes)
992 * @param off position to search digest offset from
993 * @return 0 if digest is valid, digest position otherwise
995 static int rtmp_validate_digest(uint8_t *buf, int off)
1000 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1002 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1003 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1008 if (!memcmp(digest, buf + digest_pos, 32))
1013 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1019 if (rt->swfhash_len != 32) {
1020 av_log(s, AV_LOG_ERROR,
1021 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1022 return AVERROR(EINVAL);
1025 p = &rt->swfverification[0];
1026 bytestream_put_byte(&p, 1);
1027 bytestream_put_byte(&p, 1);
1028 bytestream_put_be32(&p, rt->swfsize);
1029 bytestream_put_be32(&p, rt->swfsize);
1031 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1038 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1039 uint8_t **out_data, int64_t *out_size)
1041 z_stream zs = { 0 };
1046 zs.avail_in = in_size;
1047 zs.next_in = in_data;
1048 ret = inflateInit(&zs);
1050 return AVERROR_UNKNOWN;
1053 uint8_t tmp_buf[16384];
1055 zs.avail_out = sizeof(tmp_buf);
1056 zs.next_out = tmp_buf;
1058 ret = inflate(&zs, Z_NO_FLUSH);
1059 if (ret != Z_OK && ret != Z_STREAM_END) {
1060 ret = AVERROR_UNKNOWN;
1064 size = sizeof(tmp_buf) - zs.avail_out;
1065 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1066 ret = AVERROR(ENOMEM);
1071 memcpy(*out_data + *out_size, tmp_buf, size);
1073 } while (zs.avail_out == 0);
1081 static int rtmp_calc_swfhash(URLContext *s)
1083 RTMPContext *rt = s->priv_data;
1084 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1091 /* Get the SWF player file. */
1092 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1093 &s->interrupt_callback, NULL, s->protocols, s)) < 0) {
1094 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1098 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1103 if (!(in_data = av_malloc(in_size))) {
1104 ret = AVERROR(ENOMEM);
1108 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1112 ret = AVERROR_INVALIDDATA;
1116 if (!memcmp(in_data, "CWS", 3)) {
1119 /* Decompress the SWF player file using Zlib. */
1120 if (!(out_data = av_malloc(8))) {
1121 ret = AVERROR(ENOMEM);
1124 *in_data = 'F'; // magic stuff
1125 memcpy(out_data, in_data, 8);
1128 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1129 &out_data, &out_size)) < 0)
1134 av_log(s, AV_LOG_ERROR,
1135 "Zlib is required for decompressing the SWF player file.\n");
1136 ret = AVERROR(EINVAL);
1144 /* Compute the SHA256 hash of the SWF player file. */
1145 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1146 "Genuine Adobe Flash Player 001", 30,
1150 /* Set SWFVerification parameters. */
1151 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1152 rt->swfsize = swfsize;
1156 av_freep(&out_data);
1157 ffurl_close(stream);
1162 * Perform handshake with the server by means of exchanging pseudorandom data
1163 * signed with HMAC-SHA2 digest.
1165 * @return 0 if handshake succeeds, negative value otherwise
1167 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1170 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1171 3, // unencrypted data
1172 0, 0, 0, 0, // client uptime
1178 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1179 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1181 int server_pos, client_pos;
1182 uint8_t digest[32], signature[32];
1185 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1187 av_lfg_init(&rnd, 0xDEADC0DE);
1188 // generate handshake packet - 1536 bytes of pseudorandom data
1189 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1190 tosend[i] = av_lfg_get(&rnd) >> 24;
1192 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1193 /* When the client wants to use RTMPE, we have to change the command
1194 * byte to 0x06 which means to use encrypted data and we have to set
1195 * the flash version to at least 9.0.115.0. */
1202 /* Initialize the Diffie-Hellmann context and generate the public key
1203 * to send to the server. */
1204 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1208 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1212 if ((ret = ffurl_write(rt->stream, tosend,
1213 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1214 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1218 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1219 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1220 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1224 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1225 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1226 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1230 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1231 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1232 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1234 if (rt->is_input && serverdata[5] >= 3) {
1235 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1241 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1246 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1247 return AVERROR(EIO);
1251 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1252 * key are the last 32 bytes of the server handshake. */
1254 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1255 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1259 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1260 rtmp_server_key, sizeof(rtmp_server_key),
1265 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1266 0, digest, 32, signature);
1270 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1271 /* Compute the shared secret key sent by the server and initialize
1272 * the RC4 encryption. */
1273 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1274 tosend + 1, type)) < 0)
1277 /* Encrypt the signature received by the server. */
1278 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1281 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1282 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1283 return AVERROR(EIO);
1286 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1287 tosend[i] = av_lfg_get(&rnd) >> 24;
1288 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1289 rtmp_player_key, sizeof(rtmp_player_key),
1294 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1296 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1300 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1301 /* Encrypt the signature to be send to the server. */
1302 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1303 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1307 // write reply back to the server
1308 if ((ret = ffurl_write(rt->stream, tosend,
1309 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1312 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1313 /* Set RC4 keys for encryption and update the keystreams. */
1314 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1318 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1319 /* Compute the shared secret key sent by the server and initialize
1320 * the RC4 encryption. */
1321 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1322 tosend + 1, 1)) < 0)
1325 if (serverdata[0] == 9) {
1326 /* Encrypt the signature received by the server. */
1327 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1332 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1333 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1336 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1337 /* Set RC4 keys for encryption and update the keystreams. */
1338 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1346 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1347 uint32_t *second_int, char *arraydata,
1352 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1353 RTMP_HANDSHAKE_PACKET_SIZE);
1355 return AVERROR(EIO);
1356 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1357 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1358 " not following standard\n", (int)inoutsize);
1359 return AVERROR(EINVAL);
1362 *first_int = AV_RB32(arraydata);
1363 *second_int = AV_RB32(arraydata + 4);
1367 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1368 uint32_t second_int, char *arraydata, int size)
1372 AV_WB32(arraydata, first_int);
1373 AV_WB32(arraydata + 4, second_int);
1374 inoutsize = ffurl_write(rt->stream, arraydata,
1375 RTMP_HANDSHAKE_PACKET_SIZE);
1376 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1377 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1378 return AVERROR(EIO);
1385 * rtmp handshake server side
1387 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1389 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1391 uint32_t hs_my_epoch;
1392 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1393 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1400 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1401 if (inoutsize <= 0) {
1402 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1403 return AVERROR(EIO);
1406 if (buffer[0] != 3) {
1407 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1408 return AVERROR(EIO);
1410 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1411 av_log(s, AV_LOG_ERROR,
1412 "Unable to write answer - RTMP S0\n");
1413 return AVERROR(EIO);
1416 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1417 RTMP_HANDSHAKE_PACKET_SIZE);
1419 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1423 /* By now same epoch will be sent */
1424 hs_my_epoch = hs_epoch;
1425 /* Generate random */
1426 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1428 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1430 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1431 RTMP_HANDSHAKE_PACKET_SIZE);
1433 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1437 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1438 RTMP_HANDSHAKE_PACKET_SIZE);
1440 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1444 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1445 RTMP_HANDSHAKE_PACKET_SIZE);
1447 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1450 if (temp != hs_my_epoch)
1451 av_log(s, AV_LOG_WARNING,
1452 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1453 if (memcmp(buffer + 8, hs_s1 + 8,
1454 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1455 av_log(s, AV_LOG_WARNING,
1456 "Erroneous C2 Message random does not match up\n");
1461 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1463 RTMPContext *rt = s->priv_data;
1466 if (pkt->size < 4) {
1467 av_log(s, AV_LOG_ERROR,
1468 "Too short chunk size change packet (%d)\n",
1470 return AVERROR_INVALIDDATA;
1473 if (!rt->is_input) {
1474 /* Send the same chunk size change packet back to the server,
1475 * setting the outgoing chunk size to the same as the incoming one. */
1476 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1477 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1479 rt->out_chunk_size = AV_RB32(pkt->data);
1482 rt->in_chunk_size = AV_RB32(pkt->data);
1483 if (rt->in_chunk_size <= 0) {
1484 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1486 return AVERROR_INVALIDDATA;
1488 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1494 static int handle_user_control(URLContext *s, RTMPPacket *pkt)
1496 RTMPContext *rt = s->priv_data;
1499 if (pkt->size < 2) {
1500 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1502 return AVERROR_INVALIDDATA;
1505 t = AV_RB16(pkt->data);
1506 if (t == 6) { // PingRequest
1507 if ((ret = gen_pong(s, rt, pkt)) < 0)
1509 } else if (t == 26) {
1511 if ((ret = gen_swf_verification(s, rt)) < 0)
1514 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1521 static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
1523 RTMPContext *rt = s->priv_data;
1525 if (pkt->size < 4) {
1526 av_log(s, AV_LOG_ERROR,
1527 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1529 return AVERROR_INVALIDDATA;
1532 // We currently don't check how much the peer has acknowledged of
1533 // what we have sent. To do that properly, we should call
1534 // gen_window_ack_size here, to tell the peer that we want an
1535 // acknowledgement with (at least) that interval.
1536 rt->max_sent_unacked = AV_RB32(pkt->data);
1537 if (rt->max_sent_unacked <= 0) {
1538 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1539 rt->max_sent_unacked);
1540 return AVERROR_INVALIDDATA;
1543 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1548 static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
1550 RTMPContext *rt = s->priv_data;
1552 if (pkt->size < 4) {
1553 av_log(s, AV_LOG_ERROR,
1554 "Too short window acknowledgement size packet (%d)\n",
1556 return AVERROR_INVALIDDATA;
1559 rt->receive_report_size = AV_RB32(pkt->data);
1560 if (rt->receive_report_size <= 0) {
1561 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1562 rt->receive_report_size);
1563 return AVERROR_INVALIDDATA;
1565 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1566 // Send an Acknowledgement packet after receiving half the maximum
1567 // size, to make sure the peer can keep on sending without waiting
1568 // for acknowledgements.
1569 rt->receive_report_size >>= 1;
1574 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1575 const char *opaque, const char *challenge)
1578 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1579 struct AVMD5 *md5 = av_md5_alloc();
1581 return AVERROR(ENOMEM);
1583 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1586 av_md5_update(md5, user, strlen(user));
1587 av_md5_update(md5, salt, strlen(salt));
1588 av_md5_update(md5, rt->password, strlen(rt->password));
1589 av_md5_final(md5, hash);
1590 av_base64_encode(hashstr, sizeof(hashstr), hash,
1593 av_md5_update(md5, hashstr, strlen(hashstr));
1595 av_md5_update(md5, opaque, strlen(opaque));
1597 av_md5_update(md5, challenge, strlen(challenge));
1598 av_md5_update(md5, challenge2, strlen(challenge2));
1599 av_md5_final(md5, hash);
1600 av_base64_encode(hashstr, sizeof(hashstr), hash,
1602 snprintf(rt->auth_params, sizeof(rt->auth_params),
1603 "?authmod=%s&user=%s&challenge=%s&response=%s",
1604 "adobe", user, challenge2, hashstr);
1606 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1607 "&opaque=%s", opaque);
1613 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1616 char hashstr1[33], hashstr2[33];
1617 const char *realm = "live";
1618 const char *method = "publish";
1619 const char *qop = "auth";
1620 const char *nc = "00000001";
1622 struct AVMD5 *md5 = av_md5_alloc();
1624 return AVERROR(ENOMEM);
1626 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1629 av_md5_update(md5, user, strlen(user));
1630 av_md5_update(md5, ":", 1);
1631 av_md5_update(md5, realm, strlen(realm));
1632 av_md5_update(md5, ":", 1);
1633 av_md5_update(md5, rt->password, strlen(rt->password));
1634 av_md5_final(md5, hash);
1635 ff_data_to_hex(hashstr1, hash, 16, 1);
1636 hashstr1[32] = '\0';
1639 av_md5_update(md5, method, strlen(method));
1640 av_md5_update(md5, ":/", 2);
1641 av_md5_update(md5, rt->app, strlen(rt->app));
1642 if (!strchr(rt->app, '/'))
1643 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1644 av_md5_final(md5, hash);
1645 ff_data_to_hex(hashstr2, hash, 16, 1);
1646 hashstr2[32] = '\0';
1649 av_md5_update(md5, hashstr1, strlen(hashstr1));
1650 av_md5_update(md5, ":", 1);
1652 av_md5_update(md5, nonce, strlen(nonce));
1653 av_md5_update(md5, ":", 1);
1654 av_md5_update(md5, nc, strlen(nc));
1655 av_md5_update(md5, ":", 1);
1656 av_md5_update(md5, cnonce, strlen(cnonce));
1657 av_md5_update(md5, ":", 1);
1658 av_md5_update(md5, qop, strlen(qop));
1659 av_md5_update(md5, ":", 1);
1660 av_md5_update(md5, hashstr2, strlen(hashstr2));
1661 av_md5_final(md5, hash);
1662 ff_data_to_hex(hashstr1, hash, 16, 1);
1664 snprintf(rt->auth_params, sizeof(rt->auth_params),
1665 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1666 "llnw", user, nonce, cnonce, nc, hashstr1);
1672 static int handle_connect_error(URLContext *s, const char *desc)
1674 RTMPContext *rt = s->priv_data;
1675 char buf[300], *ptr, authmod[15];
1677 const char *user = "", *salt = "", *opaque = NULL,
1678 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1680 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1681 !(cptr = strstr(desc, "authmod=llnw"))) {
1682 av_log(s, AV_LOG_ERROR,
1683 "Unknown connect error (unsupported authentication method?)\n");
1684 return AVERROR_UNKNOWN;
1686 cptr += strlen("authmod=");
1687 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1688 authmod[i++] = *cptr++;
1691 if (!rt->username[0] || !rt->password[0]) {
1692 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1693 return AVERROR_UNKNOWN;
1696 if (strstr(desc, "?reason=authfailed")) {
1697 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1698 return AVERROR_UNKNOWN;
1699 } else if (strstr(desc, "?reason=nosuchuser")) {
1700 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1701 return AVERROR_UNKNOWN;
1704 if (rt->auth_tried) {
1705 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1706 return AVERROR_UNKNOWN;
1709 rt->auth_params[0] = '\0';
1711 if (strstr(desc, "code=403 need auth")) {
1712 snprintf(rt->auth_params, sizeof(rt->auth_params),
1713 "?authmod=%s&user=%s", authmod, rt->username);
1717 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1718 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1719 return AVERROR_UNKNOWN;
1722 av_strlcpy(buf, cptr + 1, sizeof(buf));
1726 char *next = strchr(ptr, '&');
1727 char *value = strchr(ptr, '=');
1732 if (!strcmp(ptr, "user")) {
1734 } else if (!strcmp(ptr, "salt")) {
1736 } else if (!strcmp(ptr, "opaque")) {
1738 } else if (!strcmp(ptr, "challenge")) {
1740 } else if (!strcmp(ptr, "nonce")) {
1746 if (!strcmp(authmod, "adobe")) {
1747 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1750 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1758 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1760 RTMPContext *rt = s->priv_data;
1761 const uint8_t *data_end = pkt->data + pkt->size;
1762 char *tracked_method = NULL;
1763 int level = AV_LOG_ERROR;
1764 uint8_t tmpstr[256];
1767 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1770 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1771 "description", tmpstr, sizeof(tmpstr))) {
1772 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1773 !strcmp(tracked_method, "releaseStream") ||
1774 !strcmp(tracked_method, "FCSubscribe") ||
1775 !strcmp(tracked_method, "FCPublish"))) {
1776 /* Gracefully ignore Adobe-specific historical artifact errors. */
1777 level = AV_LOG_WARNING;
1779 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1780 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1782 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1783 ret = handle_connect_error(s, tmpstr);
1785 rt->do_reconnect = 1;
1786 level = AV_LOG_VERBOSE;
1789 ret = AVERROR_UNKNOWN;
1790 av_log(s, level, "Server error: %s\n", tmpstr);
1793 av_free(tracked_method);
1797 static int write_begin(URLContext *s)
1799 RTMPContext *rt = s->priv_data;
1801 RTMPPacket spkt = { 0 };
1804 // Send Stream Begin 1
1805 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1806 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1807 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1811 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1812 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1813 bytestream2_put_be32(&pbc, rt->nb_streamid);
1815 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1816 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1818 ff_rtmp_packet_destroy(&spkt);
1823 static int write_status(URLContext *s, RTMPPacket *pkt,
1824 const char *status, const char *filename)
1826 RTMPContext *rt = s->priv_data;
1827 RTMPPacket spkt = { 0 };
1828 char statusmsg[128];
1832 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1834 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1835 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1840 spkt.extra = pkt->extra;
1841 ff_amf_write_string(&pp, "onStatus");
1842 ff_amf_write_number(&pp, 0);
1843 ff_amf_write_null(&pp);
1845 ff_amf_write_object_start(&pp);
1846 ff_amf_write_field_name(&pp, "level");
1847 ff_amf_write_string(&pp, "status");
1848 ff_amf_write_field_name(&pp, "code");
1849 ff_amf_write_string(&pp, status);
1850 ff_amf_write_field_name(&pp, "description");
1851 snprintf(statusmsg, sizeof(statusmsg),
1852 "%s is now published", filename);
1853 ff_amf_write_string(&pp, statusmsg);
1854 ff_amf_write_field_name(&pp, "details");
1855 ff_amf_write_string(&pp, filename);
1856 ff_amf_write_object_end(&pp);
1858 spkt.size = pp - spkt.data;
1859 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1860 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1861 ff_rtmp_packet_destroy(&spkt);
1866 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1868 RTMPContext *rt = s->priv_data;
1874 const uint8_t *p = pkt->data;
1876 RTMPPacket spkt = { 0 };
1880 bytestream2_init(&gbc, p, pkt->size);
1881 if (ff_amf_read_string(&gbc, command, sizeof(command),
1883 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1884 return AVERROR_INVALIDDATA;
1887 ret = ff_amf_read_number(&gbc, &seqnum);
1890 ret = ff_amf_read_null(&gbc);
1893 if (!strcmp(command, "FCPublish") ||
1894 !strcmp(command, "publish")) {
1895 ret = ff_amf_read_string(&gbc, filename,
1896 sizeof(filename), &stringlen);
1898 if (ret == AVERROR(EINVAL))
1899 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1901 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1906 pchar = strrchr(s->filename, '/');
1908 av_log(s, AV_LOG_WARNING,
1909 "Unable to find / in url %s, bad format\n",
1911 pchar = s->filename;
1914 if (strcmp(pchar, filename))
1915 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1916 " %s\n", filename, pchar);
1918 rt->state = STATE_RECEIVING;
1921 if (!strcmp(command, "FCPublish")) {
1922 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1924 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1925 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1929 ff_amf_write_string(&pp, "onFCPublish");
1930 } else if (!strcmp(command, "publish")) {
1931 ret = write_begin(s);
1935 // Send onStatus(NetStream.Publish.Start)
1936 return write_status(s, pkt, "NetStream.Publish.Start",
1938 } else if (!strcmp(command, "play")) {
1939 ret = write_begin(s);
1942 rt->state = STATE_SENDING;
1943 return write_status(s, pkt, "NetStream.Play.Start",
1946 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1948 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1949 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1953 ff_amf_write_string(&pp, "_result");
1954 ff_amf_write_number(&pp, seqnum);
1955 ff_amf_write_null(&pp);
1956 if (!strcmp(command, "createStream")) {
1958 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1959 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1960 ff_amf_write_number(&pp, rt->nb_streamid);
1961 /* By now we don't control which streams are removed in
1962 * deleteStream. There is no stream creation control
1963 * if a client creates more than 2^32 - 2 streams. */
1966 spkt.size = pp - spkt.data;
1967 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1968 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1969 ff_rtmp_packet_destroy(&spkt);
1974 * Read the AMF_NUMBER response ("_result") to a function call
1975 * (e.g. createStream()). This response should be made up of the AMF_STRING
1976 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
1977 * successful response, we will return set the value to number (otherwise number
1978 * will not be changed).
1980 * @return 0 if reading the value succeeds, negative value otherwise
1982 static int read_number_result(RTMPPacket *pkt, double *number)
1984 // We only need to fit "_result" in this.
1985 uint8_t strbuffer[8];
1990 bytestream2_init(&gbc, pkt->data, pkt->size);
1992 // Value 1/4: "_result" as AMF_STRING
1993 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
1994 return AVERROR_INVALIDDATA;
1995 if (strcmp(strbuffer, "_result"))
1996 return AVERROR_INVALIDDATA;
1997 // Value 2/4: The callee reference number
1998 if (ff_amf_read_number(&gbc, &numbuffer))
1999 return AVERROR_INVALIDDATA;
2001 if (ff_amf_read_null(&gbc))
2002 return AVERROR_INVALIDDATA;
2003 // Value 4/4: The response as AMF_NUMBER
2004 if (ff_amf_read_number(&gbc, &numbuffer))
2005 return AVERROR_INVALIDDATA;
2007 *number = numbuffer;
2012 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2014 RTMPContext *rt = s->priv_data;
2015 char *tracked_method = NULL;
2018 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2021 if (!tracked_method) {
2022 /* Ignore this reply when the current method is not tracked. */
2026 if (!strcmp(tracked_method, "connect")) {
2027 if (!rt->is_input) {
2028 if ((ret = gen_release_stream(s, rt)) < 0)
2031 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2034 if ((ret = gen_window_ack_size(s, rt)) < 0)
2038 if ((ret = gen_create_stream(s, rt)) < 0)
2042 /* Send the FCSubscribe command when the name of live
2043 * stream is defined by the user or if it's a live stream. */
2044 if (rt->subscribe) {
2045 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2047 } else if (rt->live == -1) {
2048 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2052 } else if (!strcmp(tracked_method, "createStream")) {
2054 if (read_number_result(pkt, &stream_id)) {
2055 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2057 rt->stream_id = stream_id;
2060 if (!rt->is_input) {
2061 if ((ret = gen_publish(s, rt)) < 0)
2064 if (rt->live != -1) {
2065 if ((ret = gen_get_stream_length(s, rt)) < 0)
2068 if ((ret = gen_play(s, rt)) < 0)
2070 if ((ret = gen_buffer_time(s, rt)) < 0)
2073 } else if (!strcmp(tracked_method, "getStreamLength")) {
2074 if (read_number_result(pkt, &rt->duration)) {
2075 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2080 av_free(tracked_method);
2084 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2086 RTMPContext *rt = s->priv_data;
2087 const uint8_t *data_end = pkt->data + pkt->size;
2088 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2089 uint8_t tmpstr[256];
2092 for (i = 0; i < 2; i++) {
2093 t = ff_amf_tag_size(ptr, data_end);
2099 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2100 if (!t && !strcmp(tmpstr, "error")) {
2101 t = ff_amf_get_field_value(ptr, data_end,
2102 "description", tmpstr, sizeof(tmpstr));
2103 if (t || !tmpstr[0])
2104 t = ff_amf_get_field_value(ptr, data_end, "code",
2105 tmpstr, sizeof(tmpstr));
2107 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2111 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2112 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2113 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2114 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2115 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2116 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2121 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2123 RTMPContext *rt = s->priv_data;
2126 //TODO: check for the messages sent for wrong state?
2127 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2128 if ((ret = handle_invoke_error(s, pkt)) < 0)
2130 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2131 if ((ret = handle_invoke_result(s, pkt)) < 0)
2133 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2134 if ((ret = handle_invoke_status(s, pkt)) < 0)
2136 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2137 if ((ret = gen_check_bw(s, rt)) < 0)
2139 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2140 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2141 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2142 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2143 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2144 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2145 if ((ret = send_invoke_response(s, pkt)) < 0)
2152 static int update_offset(RTMPContext *rt, int size)
2156 // generate packet header and put data into buffer for FLV demuxer
2157 if (rt->flv_off < rt->flv_size) {
2158 // There is old unread data in the buffer, thus append at the end
2159 old_flv_size = rt->flv_size;
2160 rt->flv_size += size;
2162 // All data has been read, write the new data at the start of the buffer
2164 rt->flv_size = size;
2168 return old_flv_size;
2171 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2173 int old_flv_size, ret;
2175 const uint8_t *data = pkt->data + skip;
2176 const int size = pkt->size - skip;
2177 uint32_t ts = pkt->timestamp;
2179 if (pkt->type == RTMP_PT_AUDIO) {
2181 } else if (pkt->type == RTMP_PT_VIDEO) {
2185 old_flv_size = update_offset(rt, size + 15);
2187 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2188 rt->flv_size = rt->flv_off = 0;
2191 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2192 bytestream2_skip_p(&pbc, old_flv_size);
2193 bytestream2_put_byte(&pbc, pkt->type);
2194 bytestream2_put_be24(&pbc, size);
2195 bytestream2_put_be24(&pbc, ts);
2196 bytestream2_put_byte(&pbc, ts >> 24);
2197 bytestream2_put_be24(&pbc, 0);
2198 bytestream2_put_buffer(&pbc, data, size);
2199 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2204 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2206 RTMPContext *rt = s->priv_data;
2207 uint8_t commandbuffer[64];
2208 char statusmsg[128];
2209 int stringlen, ret, skip = 0;
2212 bytestream2_init(&gbc, pkt->data, pkt->size);
2213 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2215 return AVERROR_INVALIDDATA;
2217 if (!strcmp(commandbuffer, "onMetaData")) {
2218 // metadata properties should be stored in a mixed array
2219 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2220 // We have found a metaData Array so flv can determine the streams
2222 rt->received_metadata = 1;
2223 // skip 32-bit max array index
2224 bytestream2_skip(&gbc, 4);
2225 while (bytestream2_get_bytes_left(&gbc) > 3) {
2226 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2228 return AVERROR_INVALIDDATA;
2229 // We do not care about the content of the property (yet).
2230 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2232 return AVERROR_INVALIDDATA;
2233 bytestream2_skip(&gbc, stringlen);
2235 // The presence of the following properties indicates that the
2236 // respective streams are present.
2237 if (!strcmp(statusmsg, "videocodecid")) {
2240 if (!strcmp(statusmsg, "audiocodecid")) {
2244 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2245 return AVERROR_INVALIDDATA;
2249 // Skip the @setDataFrame string and validate it is a notification
2250 if (!strcmp(commandbuffer, "@setDataFrame")) {
2251 skip = gbc.buffer - pkt->data;
2252 ret = ff_amf_read_string(&gbc, statusmsg,
2253 sizeof(statusmsg), &stringlen);
2255 return AVERROR_INVALIDDATA;
2258 return append_flv_data(rt, pkt, skip);
2262 * Parse received packet and possibly perform some action depending on
2263 * the packet contents.
2264 * @return 0 for no errors, negative values for serious errors which prevent
2265 * further communications, positive values for uncritical errors
2267 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2272 ff_rtmp_packet_dump(s, pkt);
2275 switch (pkt->type) {
2276 case RTMP_PT_BYTES_READ:
2277 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2279 case RTMP_PT_CHUNK_SIZE:
2280 if ((ret = handle_chunk_size(s, pkt)) < 0)
2283 case RTMP_PT_USER_CONTROL:
2284 if ((ret = handle_user_control(s, pkt)) < 0)
2287 case RTMP_PT_SET_PEER_BW:
2288 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2291 case RTMP_PT_WINDOW_ACK_SIZE:
2292 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2295 case RTMP_PT_INVOKE:
2296 if ((ret = handle_invoke(s, pkt)) < 0)
2301 case RTMP_PT_METADATA:
2302 case RTMP_PT_NOTIFY:
2303 /* Audio, Video and Metadata packets are parsed in get_packet() */
2306 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2312 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2314 int ret, old_flv_size, type;
2315 const uint8_t *next;
2318 uint32_t ts, cts, pts = 0;
2320 old_flv_size = update_offset(rt, pkt->size);
2322 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2323 rt->flv_size = rt->flv_off = 0;
2328 p = rt->flv_data + old_flv_size;
2330 /* copy data while rewriting timestamps */
2331 ts = pkt->timestamp;
2333 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2334 type = bytestream_get_byte(&next);
2335 size = bytestream_get_be24(&next);
2336 cts = bytestream_get_be24(&next);
2337 cts |= bytestream_get_byte(&next) << 24;
2342 if (size + 3 + 4 > pkt->data + pkt->size - next)
2344 bytestream_put_byte(&p, type);
2345 bytestream_put_be24(&p, size);
2346 bytestream_put_be24(&p, ts);
2347 bytestream_put_byte(&p, ts >> 24);
2348 memcpy(p, next, size + 3 + 4);
2350 bytestream_put_be32(&p, size + RTMP_HEADER);
2351 next += size + 3 + 4;
2353 if (p != rt->flv_data + rt->flv_size) {
2354 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2355 "RTMP_PT_METADATA packet\n");
2356 rt->flv_size = p - rt->flv_data;
2363 * Interact with the server by receiving and sending RTMP packets until
2364 * there is some significant data (media data or expected status notification).
2366 * @param s reading context
2367 * @param for_header non-zero value tells function to work until it
2368 * gets notification from the server that playing has been started,
2369 * otherwise function will work until some media data is received (or
2371 * @return 0 for successful operation, negative value in case of error
2373 static int get_packet(URLContext *s, int for_header)
2375 RTMPContext *rt = s->priv_data;
2378 if (rt->state == STATE_STOPPED)
2382 RTMPPacket rpkt = { 0 };
2383 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2384 rt->in_chunk_size, &rt->prev_pkt[0],
2385 &rt->nb_prev_pkt[0])) <= 0) {
2387 return AVERROR(EAGAIN);
2389 return AVERROR(EIO);
2393 // Track timestamp for later use
2394 rt->last_timestamp = rpkt.timestamp;
2396 rt->bytes_read += ret;
2397 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2398 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2399 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) {
2400 ff_rtmp_packet_destroy(&rpkt);
2403 rt->last_bytes_read = rt->bytes_read;
2406 ret = rtmp_parse_result(s, rt, &rpkt);
2408 // At this point we must check if we are in the seek state and continue
2409 // with the next packet. handle_invoke will get us out of this state
2410 // when the right message is encountered
2411 if (rt->state == STATE_SEEKING) {
2412 ff_rtmp_packet_destroy(&rpkt);
2413 // We continue, let the natural flow of things happen:
2414 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2418 if (ret < 0) {//serious error in current packet
2419 ff_rtmp_packet_destroy(&rpkt);
2422 if (rt->do_reconnect && for_header) {
2423 ff_rtmp_packet_destroy(&rpkt);
2426 if (rt->state == STATE_STOPPED) {
2427 ff_rtmp_packet_destroy(&rpkt);
2430 if (for_header && (rt->state == STATE_PLAYING ||
2431 rt->state == STATE_PUBLISHING ||
2432 rt->state == STATE_SENDING ||
2433 rt->state == STATE_RECEIVING)) {
2434 ff_rtmp_packet_destroy(&rpkt);
2437 if (!rpkt.size || !rt->is_input) {
2438 ff_rtmp_packet_destroy(&rpkt);
2441 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2442 ret = append_flv_data(rt, &rpkt, 0);
2443 ff_rtmp_packet_destroy(&rpkt);
2445 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2446 ret = handle_notify(s, &rpkt);
2447 ff_rtmp_packet_destroy(&rpkt);
2449 } else if (rpkt.type == RTMP_PT_METADATA) {
2450 ret = handle_metadata(rt, &rpkt);
2451 ff_rtmp_packet_destroy(&rpkt);
2454 ff_rtmp_packet_destroy(&rpkt);
2458 static int rtmp_close(URLContext *h)
2460 RTMPContext *rt = h->priv_data;
2463 if (!rt->is_input) {
2464 rt->flv_data = NULL;
2465 if (rt->out_pkt.size)
2466 ff_rtmp_packet_destroy(&rt->out_pkt);
2467 if (rt->state > STATE_FCPUBLISH)
2468 ret = gen_fcunpublish_stream(h, rt);
2470 if (rt->state > STATE_HANDSHAKED)
2471 ret = gen_delete_stream(h, rt);
2472 for (i = 0; i < 2; i++) {
2473 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2474 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2475 av_freep(&rt->prev_pkt[i]);
2478 free_tracked_methods(rt);
2479 av_freep(&rt->flv_data);
2480 ffurl_close(rt->stream);
2485 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2486 * demuxer about the duration of the stream.
2488 * This should only be done if there was no real onMetadata packet sent by the
2489 * server at the start of the stream and if we were able to retrieve a valid
2490 * duration via a getStreamLength call.
2492 * @return 0 for successful operation, negative value in case of error
2494 static int inject_fake_duration_metadata(RTMPContext *rt)
2496 // We need to insert the metadata packet directly after the FLV
2497 // header, i.e. we need to move all other already read data by the
2498 // size of our fake metadata packet.
2501 // Keep old flv_data pointer
2502 uint8_t* old_flv_data = rt->flv_data;
2503 // Allocate a new flv_data pointer with enough space for the additional package
2504 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2505 rt->flv_data = old_flv_data;
2506 return AVERROR(ENOMEM);
2510 memcpy(rt->flv_data, old_flv_data, 13);
2511 // Copy remaining packets
2512 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2513 // Increase the size by the injected packet
2515 // Delete the old FLV data
2516 av_free(old_flv_data);
2518 p = rt->flv_data + 13;
2519 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2520 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2521 bytestream_put_be24(&p, 0); // timestamp
2522 bytestream_put_be32(&p, 0); // reserved
2524 // first event name as a string
2525 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2526 // "onMetaData" as AMF string
2527 bytestream_put_be16(&p, 10);
2528 bytestream_put_buffer(&p, "onMetaData", 10);
2530 // mixed array (hash) with size and string/type/data tuples
2531 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2532 bytestream_put_be32(&p, 1); // metadata_count
2534 // "duration" as AMF string
2535 bytestream_put_be16(&p, 8);
2536 bytestream_put_buffer(&p, "duration", 8);
2537 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2538 bytestream_put_be64(&p, av_double2int(rt->duration));
2541 bytestream_put_be16(&p, 0); // Empty string
2542 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2543 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2549 * Open RTMP connection and verify that the stream can be played.
2551 * URL syntax: rtmp://server[:port][/app][/playpath]
2552 * where 'app' is first one or two directories in the path
2553 * (e.g. /ondemand/, /flash/live/, etc.)
2554 * and 'playpath' is a file name (the rest of the path,
2555 * may be prefixed with "mp4:")
2557 static int rtmp_open(URLContext *s, const char *uri, int flags)
2559 RTMPContext *rt = s->priv_data;
2560 char proto[8], hostname[256], path[1024], auth[100], *fname;
2561 char *old_app, *qmark, fname_buffer[1024];
2564 AVDictionary *opts = NULL;
2567 if (rt->listen_timeout > 0)
2570 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2572 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2573 hostname, sizeof(hostname), &port,
2574 path, sizeof(path), s->filename);
2576 if (strchr(path, ' ')) {
2577 av_log(s, AV_LOG_WARNING,
2578 "Detected librtmp style URL parameters, these aren't supported "
2579 "by the libavformat internal RTMP handler currently enabled. "
2580 "See the documentation for the correct way to pass parameters.\n");
2584 char *ptr = strchr(auth, ':');
2587 av_strlcpy(rt->username, auth, sizeof(rt->username));
2588 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2592 if (rt->listen && strcmp(proto, "rtmp")) {
2593 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2595 return AVERROR(EINVAL);
2597 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2598 if (!strcmp(proto, "rtmpts"))
2599 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2601 /* open the http tunneling connection */
2602 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2603 } else if (!strcmp(proto, "rtmps")) {
2604 /* open the tls connection */
2606 port = RTMPS_DEFAULT_PORT;
2607 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2608 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2609 if (!strcmp(proto, "rtmpte"))
2610 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2612 /* open the encrypted connection */
2613 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2616 /* open the tcp connection */
2618 port = RTMP_DEFAULT_PORT;
2620 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2621 "?listen&listen_timeout=%d",
2622 rt->listen_timeout * 1000);
2624 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2628 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2629 &s->interrupt_callback, &opts, s->protocols, s)) < 0) {
2630 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2634 if (rt->swfverify) {
2635 if ((ret = rtmp_calc_swfhash(s)) < 0)
2639 rt->state = STATE_START;
2640 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2642 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2645 rt->out_chunk_size = 128;
2646 rt->in_chunk_size = 128; // Probably overwritten later
2647 rt->state = STATE_HANDSHAKED;
2649 // Keep the application name when it has been defined by the user.
2652 rt->app = av_malloc(APP_MAX_LENGTH);
2654 ret = AVERROR(ENOMEM);
2658 //extract "app" part from path
2659 qmark = strchr(path, '?');
2660 if (qmark && strstr(qmark, "slist=")) {
2662 // After slist we have the playpath, the full path is used as app
2663 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2664 fname = strstr(path, "slist=") + 6;
2665 // Strip any further query parameters from fname
2666 amp = strchr(fname, '&');
2668 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2669 sizeof(fname_buffer)));
2670 fname = fname_buffer;
2672 } else if (!strncmp(path, "/ondemand/", 10)) {
2674 memcpy(rt->app, "ondemand", 9);
2676 char *next = *path ? path + 1 : path;
2677 char *p = strchr(next, '/');
2682 // make sure we do not mismatch a playpath for an application instance
2683 char *c = strchr(p + 1, ':');
2684 fname = strchr(p + 1, '/');
2685 if (!fname || (c && c < fname)) {
2687 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2690 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2696 // The name of application has been defined by the user, override it.
2701 if (!rt->playpath) {
2702 int len = strlen(fname);
2704 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2705 if (!rt->playpath) {
2706 ret = AVERROR(ENOMEM);
2710 if (!strchr(fname, ':') && len >= 4 &&
2711 (!strcmp(fname + len - 4, ".f4v") ||
2712 !strcmp(fname + len - 4, ".mp4"))) {
2713 memcpy(rt->playpath, "mp4:", 5);
2715 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2716 fname[len - 4] = '\0';
2717 rt->playpath[0] = 0;
2719 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2723 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2725 ret = AVERROR(ENOMEM);
2728 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2729 port, "/%s", rt->app);
2732 if (!rt->flashver) {
2733 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2734 if (!rt->flashver) {
2735 ret = AVERROR(ENOMEM);
2739 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2740 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2741 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2743 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2744 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2748 rt->receive_report_size = 1048576;
2752 rt->received_metadata = 0;
2753 rt->last_bytes_read = 0;
2754 rt->max_sent_unacked = 2500000;
2757 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2758 proto, path, rt->app, rt->playpath);
2760 if ((ret = gen_connect(s, rt)) < 0)
2763 if ((ret = read_connect(s, s->priv_data)) < 0)
2768 ret = get_packet(s, 1);
2769 } while (ret == AVERROR(EAGAIN));
2773 if (rt->do_reconnect) {
2775 ffurl_close(rt->stream);
2777 rt->do_reconnect = 0;
2779 for (i = 0; i < 2; i++)
2780 memset(rt->prev_pkt[i], 0,
2781 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2782 free_tracked_methods(rt);
2787 // generate FLV header for demuxer
2789 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2792 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2794 // Read packets until we reach the first A/V packet or read metadata.
2795 // If there was a metadata package in front of the A/V packets, we can
2796 // build the FLV header from this. If we do not receive any metadata,
2797 // the FLV decoder will allocate the needed streams when their first
2798 // audio or video packet arrives.
2799 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2800 if ((ret = get_packet(s, 0)) < 0)
2804 // Either after we have read the metadata or (if there is none) the
2805 // first packet of an A/V stream, we have a better knowledge about the
2806 // streams, so set the FLV header accordingly.
2807 if (rt->has_audio) {
2808 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2810 if (rt->has_video) {
2811 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2814 // If we received the first packet of an A/V stream and no metadata but
2815 // the server returned a valid duration, create a fake metadata packet
2816 // to inform the FLV decoder about the duration.
2817 if (!rt->received_metadata && rt->duration > 0) {
2818 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2823 rt->flv_data = NULL;
2825 rt->skip_bytes = 13;
2828 s->max_packet_size = rt->stream->max_packet_size;
2833 av_dict_free(&opts);
2838 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2840 RTMPContext *rt = s->priv_data;
2841 int orig_size = size;
2845 int data_left = rt->flv_size - rt->flv_off;
2847 if (data_left >= size) {
2848 memcpy(buf, rt->flv_data + rt->flv_off, size);
2849 rt->flv_off += size;
2852 if (data_left > 0) {
2853 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2856 rt->flv_off = rt->flv_size;
2859 if ((ret = get_packet(s, 0)) < 0)
2865 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2868 RTMPContext *rt = s->priv_data;
2870 av_log(s, AV_LOG_DEBUG,
2871 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2872 stream_index, timestamp, flags);
2873 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2874 av_log(s, AV_LOG_ERROR,
2875 "Unable to send seek command on stream index %d at timestamp "
2876 "%"PRId64" with flags %08x\n",
2877 stream_index, timestamp, flags);
2880 rt->flv_off = rt->flv_size;
2881 rt->state = STATE_SEEKING;
2885 static int rtmp_pause(URLContext *s, int pause)
2887 RTMPContext *rt = s->priv_data;
2889 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2890 rt->last_timestamp);
2891 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2892 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2893 rt->last_timestamp);
2899 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2901 RTMPContext *rt = s->priv_data;
2902 int size_temp = size;
2903 int pktsize, pkttype, copy;
2905 const uint8_t *buf_temp = buf;
2910 if (rt->skip_bytes) {
2911 int skip = FFMIN(rt->skip_bytes, size_temp);
2914 rt->skip_bytes -= skip;
2918 if (rt->flv_header_bytes < RTMP_HEADER) {
2919 const uint8_t *header = rt->flv_header;
2920 int channel = RTMP_AUDIO_CHANNEL;
2921 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2922 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2923 rt->flv_header_bytes += copy;
2925 if (rt->flv_header_bytes < RTMP_HEADER)
2928 pkttype = bytestream_get_byte(&header);
2929 pktsize = bytestream_get_be24(&header);
2930 ts = bytestream_get_be24(&header);
2931 ts |= bytestream_get_byte(&header) << 24;
2932 bytestream_get_be24(&header);
2933 rt->flv_size = pktsize;
2935 if (pkttype == RTMP_PT_VIDEO)
2936 channel = RTMP_VIDEO_CHANNEL;
2938 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2939 pkttype == RTMP_PT_NOTIFY) {
2940 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2941 &rt->nb_prev_pkt[1],
2944 // Force sending a full 12 bytes header by clearing the
2945 // channel id, to make it not match a potential earlier
2946 // packet in the same channel.
2947 rt->prev_pkt[1][channel].channel_id = 0;
2950 //this can be a big packet, it's better to send it right here
2951 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2952 pkttype, ts, pktsize)) < 0)
2955 rt->out_pkt.extra = rt->stream_id;
2956 rt->flv_data = rt->out_pkt.data;
2959 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
2960 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
2961 rt->flv_off += copy;
2964 if (rt->flv_off == rt->flv_size) {
2967 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
2968 // For onMetaData and |RtmpSampleAccess packets, we want
2969 // @setDataFrame prepended to the packet before it gets sent.
2970 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
2972 uint8_t commandbuffer[64];
2976 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
2977 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2979 if (!strcmp(commandbuffer, "onMetaData") ||
2980 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
2982 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
2983 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
2986 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
2987 rt->out_pkt.size += 16;
2988 ptr = rt->out_pkt.data;
2989 ff_amf_write_string(&ptr, "@setDataFrame");
2994 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
2998 rt->flv_header_bytes = 0;
2999 rt->flv_nb_packets++;
3001 } while (buf_temp - buf < size);
3003 if (rt->flv_nb_packets < rt->flush_interval)
3005 rt->flv_nb_packets = 0;
3007 /* set stream into nonblocking mode */
3008 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3010 /* try to read one byte from the stream */
3011 ret = ffurl_read(rt->stream, &c, 1);
3013 /* switch the stream back into blocking mode */
3014 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3016 if (ret == AVERROR(EAGAIN)) {
3017 /* no incoming data to handle */
3019 } else if (ret < 0) {
3021 } else if (ret == 1) {
3022 RTMPPacket rpkt = { 0 };
3024 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3027 &rt->nb_prev_pkt[0], c)) <= 0)
3030 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3033 ff_rtmp_packet_destroy(&rpkt);
3039 #define OFFSET(x) offsetof(RTMPContext, x)
3040 #define DEC AV_OPT_FLAG_DECODING_PARAM
3041 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3043 static const AVOption rtmp_options[] = {
3044 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3045 {"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},
3046 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3047 {"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},
3048 {"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},
3049 {"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"},
3050 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3051 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3052 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3053 {"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},
3054 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3055 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3056 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3057 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3058 {"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},
3059 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3060 {"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},
3061 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3062 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3063 {"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" },
3067 #define RTMP_PROTOCOL(flavor) \
3068 static const AVClass flavor##_class = { \
3069 .class_name = #flavor, \
3070 .item_name = av_default_item_name, \
3071 .option = rtmp_options, \
3072 .version = LIBAVUTIL_VERSION_INT, \
3075 const URLProtocol ff_##flavor##_protocol = { \
3077 .url_open = rtmp_open, \
3078 .url_read = rtmp_read, \
3079 .url_read_seek = rtmp_seek, \
3080 .url_read_pause = rtmp_pause, \
3081 .url_write = rtmp_write, \
3082 .url_close = rtmp_close, \
3083 .priv_data_size = sizeof(RTMPContext), \
3084 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3085 .priv_data_class= &flavor##_class, \
3090 RTMP_PROTOCOL(rtmpe)
3091 RTMP_PROTOCOL(rtmps)
3092 RTMP_PROTOCOL(rtmpt)
3093 RTMP_PROTOCOL(rtmpte)
3094 RTMP_PROTOCOL(rtmpts)