2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/hmac.h"
31 #include "libavutil/intfloat.h"
32 #include "libavutil/lfg.h"
33 #include "libavutil/md5.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/random_seed.h"
43 #include "rtmpcrypt.h"
51 #define APP_MAX_LENGTH 1024
52 #define PLAYPATH_MAX_LENGTH 512
53 #define TCURL_MAX_LENGTH 1024
54 #define FLASHVER_MAX_LENGTH 64
55 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
56 #define RTMP_HEADER 11
58 /** RTMP protocol handler state */
60 STATE_START, ///< client has not done anything yet
61 STATE_HANDSHAKED, ///< client has performed handshake
62 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
63 STATE_PLAYING, ///< client has started receiving multimedia data from server
64 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
65 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
66 STATE_RECEIVING, ///< received a publish command (for input)
67 STATE_SENDING, ///< received a play command (for output)
68 STATE_STOPPED, ///< the broadcast has been stopped
71 typedef struct TrackedMethod {
76 /** protocol handler context */
77 typedef struct RTMPContext {
79 URLContext* stream; ///< TCP stream used in interactions with RTMP server
80 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
81 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
82 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
83 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
84 int is_input; ///< input/output flag
85 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
86 int live; ///< 0: recorded, -1: live, -2: both
87 char *app; ///< name of application
88 char *conn; ///< append arbitrary AMF data to the Connect message
89 ClientState state; ///< current state
90 int stream_id; ///< ID assigned by the server for the stream
91 uint8_t* flv_data; ///< buffer with data for demuxer
92 int flv_size; ///< current buffer size
93 int flv_off; ///< number of bytes read from current buffer
94 int flv_nb_packets; ///< number of flv packets published
95 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
96 uint32_t client_report_size; ///< number of bytes after which client should report to server
97 uint64_t bytes_read; ///< number of bytes read from server
98 uint64_t last_bytes_read; ///< number of bytes read last reported to server
99 uint32_t last_timestamp; ///< last timestamp received in a packet
100 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
101 int has_audio; ///< presence of audio data
102 int has_video; ///< presence of video data
103 int received_metadata; ///< Indicates if we have received metadata about the streams
104 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
105 int flv_header_bytes; ///< number of initialized bytes in flv_header
106 int nb_invokes; ///< keeps track of invoke messages
107 char* tcurl; ///< url of the target stream
108 char* flashver; ///< version of the flash plugin
109 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
110 int swfhash_len; ///< length of the SHA256 hash
111 int swfsize; ///< size of the decompressed SWF file
112 char* swfurl; ///< url of the swf player
113 char* swfverify; ///< URL to player swf file, compute hash/size automatically
114 char swfverification[42]; ///< hash of the SWF verification
115 char* pageurl; ///< url of the web page
116 char* subscribe; ///< name of live stream to subscribe
117 int server_bw; ///< server bandwidth
118 int client_buffer_time; ///< client buffer time in ms
119 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
120 int encrypted; ///< use an encrypted connection (RTMPE only)
121 TrackedMethod*tracked_methods; ///< tracked methods buffer
122 int nb_tracked_methods; ///< number of tracked methods
123 int tracked_methods_size; ///< size of the tracked methods buffer
124 int listen; ///< listen mode flag
125 int listen_timeout; ///< listen timeout to wait for new connections
126 int nb_streamid; ///< The next stream id to return on createStream calls
127 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
130 char auth_params[500];
135 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
136 /** Client key used for digest signing */
137 static const uint8_t rtmp_player_key[] = {
138 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
139 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
141 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
142 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
143 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
146 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
147 /** Key used for RTMP server digest signing */
148 static const uint8_t rtmp_server_key[] = {
149 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
150 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
151 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
153 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
154 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
155 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
158 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
159 static int handle_server_bw(URLContext *s, RTMPPacket *pkt);
160 static int handle_client_bw(URLContext *s, RTMPPacket *pkt);
162 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
166 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
167 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
168 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
169 sizeof(*rt->tracked_methods))) < 0) {
170 rt->nb_tracked_methods = 0;
171 rt->tracked_methods_size = 0;
176 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
177 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
178 return AVERROR(ENOMEM);
179 rt->tracked_methods[rt->nb_tracked_methods].id = id;
180 rt->nb_tracked_methods++;
185 static void del_tracked_method(RTMPContext *rt, int index)
187 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
188 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
189 rt->nb_tracked_methods--;
192 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
193 char **tracked_method)
195 RTMPContext *rt = s->priv_data;
201 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
202 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
205 for (i = 0; i < rt->nb_tracked_methods; i++) {
206 if (rt->tracked_methods[i].id != pkt_id)
209 *tracked_method = rt->tracked_methods[i].name;
210 del_tracked_method(rt, i);
217 static void free_tracked_methods(RTMPContext *rt)
221 for (i = 0; i < rt->nb_tracked_methods; i ++)
222 av_freep(&rt->tracked_methods[i].name);
223 av_freep(&rt->tracked_methods);
224 rt->tracked_methods_size = 0;
225 rt->nb_tracked_methods = 0;
228 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
232 if (pkt->type == RTMP_PT_INVOKE && track) {
238 bytestream2_init(&gbc, pkt->data, pkt->size);
239 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
242 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
245 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
249 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
250 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
252 ff_rtmp_packet_destroy(pkt);
256 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
261 /* The type must be B for Boolean, N for number, S for string, O for
262 * object, or Z for null. For Booleans the data must be either 0 or 1 for
263 * FALSE or TRUE, respectively. Likewise for Objects the data must be
264 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
265 * may be named, by prefixing the type with 'N' and specifying the name
266 * before the value (ie. NB:myFlag:1). This option may be used multiple times
267 * to construct arbitrary AMF sequences. */
268 if (param[0] && param[1] == ':') {
271 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
274 value = strchr(field, ':');
280 ff_amf_write_field_name(p, field);
287 ff_amf_write_bool(p, value[0] != '0');
290 ff_amf_write_string(p, value);
293 ff_amf_write_number(p, strtod(value, NULL));
296 ff_amf_write_null(p);
300 ff_amf_write_object_start(p);
302 ff_amf_write_object_end(p);
312 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
313 return AVERROR(EINVAL);
317 * Generate 'connect' call and send it to the server.
319 static int gen_connect(URLContext *s, RTMPContext *rt)
325 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
326 0, 4096 + APP_MAX_LENGTH)) < 0)
331 ff_amf_write_string(&p, "connect");
332 ff_amf_write_number(&p, ++rt->nb_invokes);
333 ff_amf_write_object_start(&p);
334 ff_amf_write_field_name(&p, "app");
335 ff_amf_write_string2(&p, rt->app, rt->auth_params);
338 ff_amf_write_field_name(&p, "type");
339 ff_amf_write_string(&p, "nonprivate");
341 ff_amf_write_field_name(&p, "flashVer");
342 ff_amf_write_string(&p, rt->flashver);
345 ff_amf_write_field_name(&p, "swfUrl");
346 ff_amf_write_string(&p, rt->swfurl);
349 ff_amf_write_field_name(&p, "tcUrl");
350 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
352 ff_amf_write_field_name(&p, "fpad");
353 ff_amf_write_bool(&p, 0);
354 ff_amf_write_field_name(&p, "capabilities");
355 ff_amf_write_number(&p, 15.0);
357 /* Tell the server we support all the audio codecs except
358 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
359 * which are unused in the RTMP protocol implementation. */
360 ff_amf_write_field_name(&p, "audioCodecs");
361 ff_amf_write_number(&p, 4071.0);
362 ff_amf_write_field_name(&p, "videoCodecs");
363 ff_amf_write_number(&p, 252.0);
364 ff_amf_write_field_name(&p, "videoFunction");
365 ff_amf_write_number(&p, 1.0);
368 ff_amf_write_field_name(&p, "pageUrl");
369 ff_amf_write_string(&p, rt->pageurl);
372 ff_amf_write_object_end(&p);
375 char *param = rt->conn;
377 // Write arbitrary AMF data to the Connect message.
380 param += strspn(param, " ");
383 sep = strchr(param, ' ');
386 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
387 // Invalid AMF parameter.
388 ff_rtmp_packet_destroy(&pkt);
399 pkt.size = p - pkt.data;
401 return rtmp_send_packet(rt, &pkt, 1);
405 #define RTMP_CTRL_ABORT_MESSAGE (2)
407 static int read_connect(URLContext *s, RTMPContext *rt)
409 RTMPPacket pkt = { 0 };
419 // handle RTMP Protocol Control Messages
421 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
422 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
425 ff_rtmp_packet_dump(s, &pkt);
427 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
428 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
429 ff_rtmp_packet_destroy(&pkt);
432 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
433 av_log(s, AV_LOG_ERROR, "received abort message\n");
434 ff_rtmp_packet_destroy(&pkt);
435 return AVERROR_UNKNOWN;
436 } else if (pkt.type == RTMP_PT_BYTES_READ) {
437 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
438 } else if (pkt.type == RTMP_PT_SERVER_BW) {
439 if ((ret = handle_server_bw(s, &pkt)) < 0) {
440 ff_rtmp_packet_destroy(&pkt);
443 } else if (pkt.type == RTMP_PT_CLIENT_BW) {
444 if ((ret = handle_client_bw(s, &pkt)) < 0) {
445 ff_rtmp_packet_destroy(&pkt);
448 } else if (pkt.type == RTMP_PT_INVOKE) {
449 // received RTMP Command Message
452 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
454 ff_rtmp_packet_destroy(&pkt);
458 bytestream2_init(&gbc, cp, pkt.size);
459 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
460 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
461 ff_rtmp_packet_destroy(&pkt);
462 return AVERROR_INVALIDDATA;
464 if (strcmp(command, "connect")) {
465 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
466 ff_rtmp_packet_destroy(&pkt);
467 return AVERROR_INVALIDDATA;
469 ret = ff_amf_read_number(&gbc, &seqnum);
471 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
472 /* Here one could parse an AMF Object with data as flashVers and others. */
473 ret = ff_amf_get_field_value(gbc.buffer,
474 gbc.buffer + bytestream2_get_bytes_left(&gbc),
475 "app", tmpstr, sizeof(tmpstr));
477 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
478 if (!ret && strcmp(tmpstr, rt->app))
479 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
481 ff_rtmp_packet_destroy(&pkt);
483 // Send Window Acknowledgement Size (as defined in specification)
484 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
485 RTMP_PT_SERVER_BW, 0, 4)) < 0)
488 bytestream_put_be32(&p, rt->server_bw);
489 pkt.size = p - pkt.data;
490 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
491 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
492 ff_rtmp_packet_destroy(&pkt);
495 // Send Peer Bandwidth
496 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
497 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
500 bytestream_put_be32(&p, rt->server_bw);
501 bytestream_put_byte(&p, 2); // dynamic
502 pkt.size = p - pkt.data;
503 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
504 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
505 ff_rtmp_packet_destroy(&pkt);
510 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
511 RTMP_PT_PING, 0, 6)) < 0)
515 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
516 bytestream_put_be32(&p, 0);
517 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
518 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
519 ff_rtmp_packet_destroy(&pkt);
524 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
525 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
529 bytestream_put_be32(&p, rt->out_chunk_size);
530 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
531 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
532 ff_rtmp_packet_destroy(&pkt);
536 // Send _result NetConnection.Connect.Success to connect
537 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
539 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
543 ff_amf_write_string(&p, "_result");
544 ff_amf_write_number(&p, seqnum);
546 ff_amf_write_object_start(&p);
547 ff_amf_write_field_name(&p, "fmsVer");
548 ff_amf_write_string(&p, "FMS/3,0,1,123");
549 ff_amf_write_field_name(&p, "capabilities");
550 ff_amf_write_number(&p, 31);
551 ff_amf_write_object_end(&p);
553 ff_amf_write_object_start(&p);
554 ff_amf_write_field_name(&p, "level");
555 ff_amf_write_string(&p, "status");
556 ff_amf_write_field_name(&p, "code");
557 ff_amf_write_string(&p, "NetConnection.Connect.Success");
558 ff_amf_write_field_name(&p, "description");
559 ff_amf_write_string(&p, "Connection succeeded.");
560 ff_amf_write_field_name(&p, "objectEncoding");
561 ff_amf_write_number(&p, 0);
562 ff_amf_write_object_end(&p);
564 pkt.size = p - pkt.data;
565 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
566 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
567 ff_rtmp_packet_destroy(&pkt);
571 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
572 RTMP_PT_INVOKE, 0, 30)) < 0)
575 ff_amf_write_string(&p, "onBWDone");
576 ff_amf_write_number(&p, 0);
577 ff_amf_write_null(&p);
578 ff_amf_write_number(&p, 8192);
579 pkt.size = p - pkt.data;
580 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
581 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
582 ff_rtmp_packet_destroy(&pkt);
588 * Generate 'releaseStream' call and send it to the server. It should make
589 * the server release some channel for media streams.
591 static int gen_release_stream(URLContext *s, RTMPContext *rt)
597 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
598 0, 29 + strlen(rt->playpath))) < 0)
601 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
603 ff_amf_write_string(&p, "releaseStream");
604 ff_amf_write_number(&p, ++rt->nb_invokes);
605 ff_amf_write_null(&p);
606 ff_amf_write_string(&p, rt->playpath);
608 return rtmp_send_packet(rt, &pkt, 1);
612 * Generate 'FCPublish' call and send it to the server. It should make
613 * the server prepare for receiving media streams.
615 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
621 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
622 0, 25 + strlen(rt->playpath))) < 0)
625 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
627 ff_amf_write_string(&p, "FCPublish");
628 ff_amf_write_number(&p, ++rt->nb_invokes);
629 ff_amf_write_null(&p);
630 ff_amf_write_string(&p, rt->playpath);
632 return rtmp_send_packet(rt, &pkt, 1);
636 * Generate 'FCUnpublish' call and send it to the server. It should make
637 * the server destroy stream.
639 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
645 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
646 0, 27 + strlen(rt->playpath))) < 0)
649 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
651 ff_amf_write_string(&p, "FCUnpublish");
652 ff_amf_write_number(&p, ++rt->nb_invokes);
653 ff_amf_write_null(&p);
654 ff_amf_write_string(&p, rt->playpath);
656 return rtmp_send_packet(rt, &pkt, 0);
660 * Generate 'createStream' call and send it to the server. It should make
661 * the server allocate some channel for media streams.
663 static int gen_create_stream(URLContext *s, RTMPContext *rt)
669 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
671 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
676 ff_amf_write_string(&p, "createStream");
677 ff_amf_write_number(&p, ++rt->nb_invokes);
678 ff_amf_write_null(&p);
680 return rtmp_send_packet(rt, &pkt, 1);
685 * Generate 'deleteStream' call and send it to the server. It should make
686 * the server remove some channel for media streams.
688 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
694 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
696 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
701 ff_amf_write_string(&p, "deleteStream");
702 ff_amf_write_number(&p, ++rt->nb_invokes);
703 ff_amf_write_null(&p);
704 ff_amf_write_number(&p, rt->stream_id);
706 return rtmp_send_packet(rt, &pkt, 0);
710 * Generate 'getStreamLength' call and send it to the server. If the server
711 * knows the duration of the selected stream, it will reply with the duration
714 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
720 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
721 0, 31 + strlen(rt->playpath))) < 0)
725 ff_amf_write_string(&p, "getStreamLength");
726 ff_amf_write_number(&p, ++rt->nb_invokes);
727 ff_amf_write_null(&p);
728 ff_amf_write_string(&p, rt->playpath);
730 return rtmp_send_packet(rt, &pkt, 1);
734 * Generate client buffer time and send it to the server.
736 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
742 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
747 bytestream_put_be16(&p, 3);
748 bytestream_put_be32(&p, rt->stream_id);
749 bytestream_put_be32(&p, rt->client_buffer_time);
751 return rtmp_send_packet(rt, &pkt, 0);
755 * Generate 'play' call and send it to the server, then ping the server
756 * to start actual playing.
758 static int gen_play(URLContext *s, RTMPContext *rt)
764 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
766 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
767 0, 29 + strlen(rt->playpath))) < 0)
770 pkt.extra = rt->stream_id;
773 ff_amf_write_string(&p, "play");
774 ff_amf_write_number(&p, ++rt->nb_invokes);
775 ff_amf_write_null(&p);
776 ff_amf_write_string(&p, rt->playpath);
777 ff_amf_write_number(&p, rt->live * 1000);
779 return rtmp_send_packet(rt, &pkt, 1);
782 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
788 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
791 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
794 pkt.extra = rt->stream_id;
797 ff_amf_write_string(&p, "seek");
798 ff_amf_write_number(&p, 0); //no tracking back responses
799 ff_amf_write_null(&p); //as usual, the first null param
800 ff_amf_write_number(&p, timestamp); //where we want to jump
802 return rtmp_send_packet(rt, &pkt, 1);
806 * Generate a pause packet that either pauses or unpauses the current stream.
808 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
814 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
817 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
820 pkt.extra = rt->stream_id;
823 ff_amf_write_string(&p, "pause");
824 ff_amf_write_number(&p, 0); //no tracking back responses
825 ff_amf_write_null(&p); //as usual, the first null param
826 ff_amf_write_bool(&p, pause); // pause or unpause
827 ff_amf_write_number(&p, timestamp); //where we pause the stream
829 return rtmp_send_packet(rt, &pkt, 1);
833 * Generate 'publish' call and send it to the server.
835 static int gen_publish(URLContext *s, RTMPContext *rt)
841 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
843 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
844 0, 30 + strlen(rt->playpath))) < 0)
847 pkt.extra = rt->stream_id;
850 ff_amf_write_string(&p, "publish");
851 ff_amf_write_number(&p, ++rt->nb_invokes);
852 ff_amf_write_null(&p);
853 ff_amf_write_string(&p, rt->playpath);
854 ff_amf_write_string(&p, "live");
856 return rtmp_send_packet(rt, &pkt, 1);
860 * Generate ping reply and send it to the server.
862 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
868 if (ppkt->size < 6) {
869 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
871 return AVERROR_INVALIDDATA;
874 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
875 ppkt->timestamp + 1, 6)) < 0)
879 bytestream_put_be16(&p, 7);
880 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
882 return rtmp_send_packet(rt, &pkt, 0);
886 * Generate SWF verification message and send it to the server.
888 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
894 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
895 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
900 bytestream_put_be16(&p, 27);
901 memcpy(p, rt->swfverification, 42);
903 return rtmp_send_packet(rt, &pkt, 0);
907 * Generate server bandwidth message and send it to the server.
909 static int gen_server_bw(URLContext *s, RTMPContext *rt)
915 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
920 bytestream_put_be32(&p, rt->server_bw);
922 return rtmp_send_packet(rt, &pkt, 0);
926 * Generate check bandwidth message and send it to the server.
928 static int gen_check_bw(URLContext *s, RTMPContext *rt)
934 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
939 ff_amf_write_string(&p, "_checkbw");
940 ff_amf_write_number(&p, ++rt->nb_invokes);
941 ff_amf_write_null(&p);
943 return rtmp_send_packet(rt, &pkt, 1);
947 * Generate report on bytes read so far and send it to the server.
949 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
955 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
960 bytestream_put_be32(&p, rt->bytes_read);
962 return rtmp_send_packet(rt, &pkt, 0);
965 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
966 const char *subscribe)
972 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
973 0, 27 + strlen(subscribe))) < 0)
977 ff_amf_write_string(&p, "FCSubscribe");
978 ff_amf_write_number(&p, ++rt->nb_invokes);
979 ff_amf_write_null(&p);
980 ff_amf_write_string(&p, subscribe);
982 return rtmp_send_packet(rt, &pkt, 1);
985 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
986 const uint8_t *key, int keylen, uint8_t *dst)
990 hmac = av_hmac_alloc(AV_HMAC_SHA256);
992 return AVERROR(ENOMEM);
994 av_hmac_init(hmac, key, keylen);
996 av_hmac_update(hmac, src, len);
997 } else { //skip 32 bytes used for storing digest
998 av_hmac_update(hmac, src, gap);
999 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
1001 av_hmac_final(hmac, dst, 32);
1008 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1011 int i, digest_pos = 0;
1013 for (i = 0; i < 4; i++)
1014 digest_pos += buf[i + off];
1015 digest_pos = digest_pos % mod_val + add_val;
1021 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1022 * will be stored) into that packet.
1024 * @param buf handshake data (1536 bytes)
1025 * @param encrypted use an encrypted connection (RTMPE)
1026 * @return offset to the digest inside input data
1028 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1030 int ret, digest_pos;
1033 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1035 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1037 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1038 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1047 * Verify that the received server response has the expected digest value.
1049 * @param buf handshake data received from the server (1536 bytes)
1050 * @param off position to search digest offset from
1051 * @return 0 if digest is valid, digest position otherwise
1053 static int rtmp_validate_digest(uint8_t *buf, int off)
1056 int ret, digest_pos;
1058 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1060 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1061 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1066 if (!memcmp(digest, buf + digest_pos, 32))
1071 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1077 if (rt->swfhash_len != 32) {
1078 av_log(s, AV_LOG_ERROR,
1079 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1080 return AVERROR(EINVAL);
1083 p = &rt->swfverification[0];
1084 bytestream_put_byte(&p, 1);
1085 bytestream_put_byte(&p, 1);
1086 bytestream_put_be32(&p, rt->swfsize);
1087 bytestream_put_be32(&p, rt->swfsize);
1089 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1096 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1097 uint8_t **out_data, int64_t *out_size)
1099 z_stream zs = { 0 };
1104 zs.avail_in = in_size;
1105 zs.next_in = in_data;
1106 ret = inflateInit(&zs);
1108 return AVERROR_UNKNOWN;
1111 uint8_t tmp_buf[16384];
1113 zs.avail_out = sizeof(tmp_buf);
1114 zs.next_out = tmp_buf;
1116 ret = inflate(&zs, Z_NO_FLUSH);
1117 if (ret != Z_OK && ret != Z_STREAM_END) {
1118 ret = AVERROR_UNKNOWN;
1122 size = sizeof(tmp_buf) - zs.avail_out;
1123 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1124 ret = AVERROR(ENOMEM);
1129 memcpy(*out_data + *out_size, tmp_buf, size);
1131 } while (zs.avail_out == 0);
1139 static int rtmp_calc_swfhash(URLContext *s)
1141 RTMPContext *rt = s->priv_data;
1142 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1143 int64_t in_size, out_size;
1149 /* Get the SWF player file. */
1150 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1151 &s->interrupt_callback, NULL,
1152 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1153 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1157 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1162 if (!(in_data = av_malloc(in_size))) {
1163 ret = AVERROR(ENOMEM);
1167 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1171 ret = AVERROR_INVALIDDATA;
1175 if (!memcmp(in_data, "CWS", 3)) {
1176 /* Decompress the SWF player file using Zlib. */
1177 if (!(out_data = av_malloc(8))) {
1178 ret = AVERROR(ENOMEM);
1181 *in_data = 'F'; // magic stuff
1182 memcpy(out_data, in_data, 8);
1186 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1187 &out_data, &out_size)) < 0)
1190 av_log(s, AV_LOG_ERROR,
1191 "Zlib is required for decompressing the SWF player file.\n");
1192 ret = AVERROR(EINVAL);
1202 /* Compute the SHA256 hash of the SWF player file. */
1203 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1204 "Genuine Adobe Flash Player 001", 30,
1208 /* Set SWFVerification parameters. */
1209 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1210 rt->swfsize = swfsize;
1214 av_freep(&out_data);
1215 ffurl_close(stream);
1220 * Perform handshake with the server by means of exchanging pseudorandom data
1221 * signed with HMAC-SHA2 digest.
1223 * @return 0 if handshake succeeds, negative value otherwise
1225 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1228 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1229 3, // unencrypted data
1230 0, 0, 0, 0, // client uptime
1231 0, 0, 0, 0, // zeros
1233 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1234 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1236 int server_pos, client_pos;
1237 uint8_t digest[32], signature[32];
1240 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1242 av_lfg_init(&rnd, 0xDEADC0DE);
1243 // generate handshake packet - 1536 bytes of pseudorandom data
1244 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1245 tosend[i] = av_lfg_get(&rnd) >> 24;
1247 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1248 /* When the client wants to use RTMPE, we have to change the command
1249 * byte to 0x06 which means to use encrypted data and we have to set
1250 * the flash version to at least 9.0.115.0. */
1257 /* Initialize the Diffie-Hellmann context and generate the public key
1258 * to send to the server. */
1259 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1263 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1267 if ((ret = ffurl_write(rt->stream, tosend,
1268 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1269 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1273 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1274 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1275 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1279 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1280 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1281 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1285 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1286 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1287 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1289 if (rt->is_input && serverdata[5] >= 3) {
1290 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1296 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1301 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1302 return AVERROR(EIO);
1306 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1307 * key are the last 32 bytes of the server handshake. */
1309 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1310 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1314 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1315 rtmp_server_key, sizeof(rtmp_server_key),
1320 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1321 0, digest, 32, signature);
1325 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1326 /* Compute the shared secret key sent by the server and initialize
1327 * the RC4 encryption. */
1328 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1329 tosend + 1, type)) < 0)
1332 /* Encrypt the signature received by the server. */
1333 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1336 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1337 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1338 return AVERROR(EIO);
1341 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1342 tosend[i] = av_lfg_get(&rnd) >> 24;
1343 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1344 rtmp_player_key, sizeof(rtmp_player_key),
1349 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1351 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1355 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1356 /* Encrypt the signature to be send to the server. */
1357 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1358 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1362 // write reply back to the server
1363 if ((ret = ffurl_write(rt->stream, tosend,
1364 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1367 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1368 /* Set RC4 keys for encryption and update the keystreams. */
1369 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1373 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1374 /* Compute the shared secret key sent by the server and initialize
1375 * the RC4 encryption. */
1376 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1377 tosend + 1, 1)) < 0)
1380 if (serverdata[0] == 9) {
1381 /* Encrypt the signature received by the server. */
1382 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1387 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1388 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1391 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1392 /* Set RC4 keys for encryption and update the keystreams. */
1393 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1401 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1402 uint32_t *second_int, char *arraydata,
1407 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1408 RTMP_HANDSHAKE_PACKET_SIZE);
1410 return AVERROR(EIO);
1411 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1412 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1413 " not following standard\n", (int)inoutsize);
1414 return AVERROR(EINVAL);
1417 *first_int = AV_RB32(arraydata);
1418 *second_int = AV_RB32(arraydata + 4);
1422 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1423 uint32_t second_int, char *arraydata, int size)
1427 AV_WB32(arraydata, first_int);
1428 AV_WB32(arraydata + 4, second_int);
1429 inoutsize = ffurl_write(rt->stream, arraydata,
1430 RTMP_HANDSHAKE_PACKET_SIZE);
1431 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1432 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1433 return AVERROR(EIO);
1440 * rtmp handshake server side
1442 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1444 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1446 uint32_t hs_my_epoch;
1447 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1448 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1455 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1456 if (inoutsize <= 0) {
1457 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1458 return AVERROR(EIO);
1461 if (buffer[0] != 3) {
1462 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1463 return AVERROR(EIO);
1465 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1466 av_log(s, AV_LOG_ERROR,
1467 "Unable to write answer - RTMP S0\n");
1468 return AVERROR(EIO);
1471 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1472 RTMP_HANDSHAKE_PACKET_SIZE);
1474 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1478 /* By now same epoch will be sent */
1479 hs_my_epoch = hs_epoch;
1480 /* Generate random */
1481 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1483 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1485 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1486 RTMP_HANDSHAKE_PACKET_SIZE);
1488 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1492 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1493 RTMP_HANDSHAKE_PACKET_SIZE);
1495 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1499 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1500 RTMP_HANDSHAKE_PACKET_SIZE);
1502 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1505 if (temp != hs_my_epoch)
1506 av_log(s, AV_LOG_WARNING,
1507 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1508 if (memcmp(buffer + 8, hs_s1 + 8,
1509 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1510 av_log(s, AV_LOG_WARNING,
1511 "Erroneous C2 Message random does not match up\n");
1516 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1518 RTMPContext *rt = s->priv_data;
1521 if (pkt->size < 4) {
1522 av_log(s, AV_LOG_ERROR,
1523 "Too short chunk size change packet (%d)\n",
1525 return AVERROR_INVALIDDATA;
1528 if (!rt->is_input) {
1529 /* Send the same chunk size change packet back to the server,
1530 * setting the outgoing chunk size to the same as the incoming one. */
1531 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1532 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1534 rt->out_chunk_size = AV_RB32(pkt->data);
1537 rt->in_chunk_size = AV_RB32(pkt->data);
1538 if (rt->in_chunk_size <= 0) {
1539 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1541 return AVERROR_INVALIDDATA;
1543 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1549 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1551 RTMPContext *rt = s->priv_data;
1554 if (pkt->size < 2) {
1555 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1557 return AVERROR_INVALIDDATA;
1560 t = AV_RB16(pkt->data);
1562 if ((ret = gen_pong(s, rt, pkt)) < 0)
1564 } else if (t == 26) {
1566 if ((ret = gen_swf_verification(s, rt)) < 0)
1569 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1576 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1578 RTMPContext *rt = s->priv_data;
1580 if (pkt->size < 4) {
1581 av_log(s, AV_LOG_ERROR,
1582 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1584 return AVERROR_INVALIDDATA;
1587 rt->client_report_size = AV_RB32(pkt->data);
1588 if (rt->client_report_size <= 0) {
1589 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1590 rt->client_report_size);
1591 return AVERROR_INVALIDDATA;
1594 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1595 rt->client_report_size >>= 1;
1600 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1602 RTMPContext *rt = s->priv_data;
1604 if (pkt->size < 4) {
1605 av_log(s, AV_LOG_ERROR,
1606 "Too short server bandwidth report packet (%d)\n",
1608 return AVERROR_INVALIDDATA;
1611 rt->server_bw = AV_RB32(pkt->data);
1612 if (rt->server_bw <= 0) {
1613 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1615 return AVERROR_INVALIDDATA;
1617 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1622 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1623 const char *opaque, const char *challenge)
1626 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1627 struct AVMD5 *md5 = av_md5_alloc();
1629 return AVERROR(ENOMEM);
1631 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1634 av_md5_update(md5, user, strlen(user));
1635 av_md5_update(md5, salt, strlen(salt));
1636 av_md5_update(md5, rt->password, strlen(rt->password));
1637 av_md5_final(md5, hash);
1638 av_base64_encode(hashstr, sizeof(hashstr), hash,
1641 av_md5_update(md5, hashstr, strlen(hashstr));
1643 av_md5_update(md5, opaque, strlen(opaque));
1645 av_md5_update(md5, challenge, strlen(challenge));
1646 av_md5_update(md5, challenge2, strlen(challenge2));
1647 av_md5_final(md5, hash);
1648 av_base64_encode(hashstr, sizeof(hashstr), hash,
1650 snprintf(rt->auth_params, sizeof(rt->auth_params),
1651 "?authmod=%s&user=%s&challenge=%s&response=%s",
1652 "adobe", user, challenge2, hashstr);
1654 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1655 "&opaque=%s", opaque);
1661 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1664 char hashstr1[33], hashstr2[33];
1665 const char *realm = "live";
1666 const char *method = "publish";
1667 const char *qop = "auth";
1668 const char *nc = "00000001";
1670 struct AVMD5 *md5 = av_md5_alloc();
1672 return AVERROR(ENOMEM);
1674 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1677 av_md5_update(md5, user, strlen(user));
1678 av_md5_update(md5, ":", 1);
1679 av_md5_update(md5, realm, strlen(realm));
1680 av_md5_update(md5, ":", 1);
1681 av_md5_update(md5, rt->password, strlen(rt->password));
1682 av_md5_final(md5, hash);
1683 ff_data_to_hex(hashstr1, hash, 16, 1);
1684 hashstr1[32] = '\0';
1687 av_md5_update(md5, method, strlen(method));
1688 av_md5_update(md5, ":/", 2);
1689 av_md5_update(md5, rt->app, strlen(rt->app));
1690 if (!strchr(rt->app, '/'))
1691 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1692 av_md5_final(md5, hash);
1693 ff_data_to_hex(hashstr2, hash, 16, 1);
1694 hashstr2[32] = '\0';
1697 av_md5_update(md5, hashstr1, strlen(hashstr1));
1698 av_md5_update(md5, ":", 1);
1700 av_md5_update(md5, nonce, strlen(nonce));
1701 av_md5_update(md5, ":", 1);
1702 av_md5_update(md5, nc, strlen(nc));
1703 av_md5_update(md5, ":", 1);
1704 av_md5_update(md5, cnonce, strlen(cnonce));
1705 av_md5_update(md5, ":", 1);
1706 av_md5_update(md5, qop, strlen(qop));
1707 av_md5_update(md5, ":", 1);
1708 av_md5_update(md5, hashstr2, strlen(hashstr2));
1709 av_md5_final(md5, hash);
1710 ff_data_to_hex(hashstr1, hash, 16, 1);
1712 snprintf(rt->auth_params, sizeof(rt->auth_params),
1713 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1714 "llnw", user, nonce, cnonce, nc, hashstr1);
1720 static int handle_connect_error(URLContext *s, const char *desc)
1722 RTMPContext *rt = s->priv_data;
1723 char buf[300], *ptr, authmod[15];
1725 const char *user = "", *salt = "", *opaque = NULL,
1726 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1728 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1729 !(cptr = strstr(desc, "authmod=llnw"))) {
1730 av_log(s, AV_LOG_ERROR,
1731 "Unknown connect error (unsupported authentication method?)\n");
1732 return AVERROR_UNKNOWN;
1734 cptr += strlen("authmod=");
1735 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1736 authmod[i++] = *cptr++;
1739 if (!rt->username[0] || !rt->password[0]) {
1740 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1741 return AVERROR_UNKNOWN;
1744 if (strstr(desc, "?reason=authfailed")) {
1745 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1746 return AVERROR_UNKNOWN;
1747 } else if (strstr(desc, "?reason=nosuchuser")) {
1748 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1749 return AVERROR_UNKNOWN;
1752 if (rt->auth_tried) {
1753 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1754 return AVERROR_UNKNOWN;
1757 rt->auth_params[0] = '\0';
1759 if (strstr(desc, "code=403 need auth")) {
1760 snprintf(rt->auth_params, sizeof(rt->auth_params),
1761 "?authmod=%s&user=%s", authmod, rt->username);
1765 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1766 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1767 return AVERROR_UNKNOWN;
1770 av_strlcpy(buf, cptr + 1, sizeof(buf));
1774 char *next = strchr(ptr, '&');
1775 char *value = strchr(ptr, '=');
1780 if (!strcmp(ptr, "user")) {
1782 } else if (!strcmp(ptr, "salt")) {
1784 } else if (!strcmp(ptr, "opaque")) {
1786 } else if (!strcmp(ptr, "challenge")) {
1788 } else if (!strcmp(ptr, "nonce")) {
1791 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1794 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1799 if (!strcmp(authmod, "adobe")) {
1800 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1803 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1811 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1813 RTMPContext *rt = s->priv_data;
1814 const uint8_t *data_end = pkt->data + pkt->size;
1815 char *tracked_method = NULL;
1816 int level = AV_LOG_ERROR;
1817 uint8_t tmpstr[256];
1820 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1823 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1824 "description", tmpstr, sizeof(tmpstr))) {
1825 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1826 !strcmp(tracked_method, "releaseStream") ||
1827 !strcmp(tracked_method, "FCSubscribe") ||
1828 !strcmp(tracked_method, "FCPublish"))) {
1829 /* Gracefully ignore Adobe-specific historical artifact errors. */
1830 level = AV_LOG_WARNING;
1832 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1833 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1835 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1836 ret = handle_connect_error(s, tmpstr);
1838 rt->do_reconnect = 1;
1839 level = AV_LOG_VERBOSE;
1842 ret = AVERROR_UNKNOWN;
1843 av_log(s, level, "Server error: %s\n", tmpstr);
1846 av_free(tracked_method);
1850 static int write_begin(URLContext *s)
1852 RTMPContext *rt = s->priv_data;
1854 RTMPPacket spkt = { 0 };
1857 // Send Stream Begin 1
1858 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1859 RTMP_PT_PING, 0, 6)) < 0) {
1860 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1864 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1865 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1866 bytestream2_put_be32(&pbc, rt->nb_streamid);
1868 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1869 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1871 ff_rtmp_packet_destroy(&spkt);
1876 static int write_status(URLContext *s, RTMPPacket *pkt,
1877 const char *status, const char *filename)
1879 RTMPContext *rt = s->priv_data;
1880 RTMPPacket spkt = { 0 };
1881 char statusmsg[128];
1885 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1887 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1888 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1893 spkt.extra = pkt->extra;
1894 ff_amf_write_string(&pp, "onStatus");
1895 ff_amf_write_number(&pp, 0);
1896 ff_amf_write_null(&pp);
1898 ff_amf_write_object_start(&pp);
1899 ff_amf_write_field_name(&pp, "level");
1900 ff_amf_write_string(&pp, "status");
1901 ff_amf_write_field_name(&pp, "code");
1902 ff_amf_write_string(&pp, status);
1903 ff_amf_write_field_name(&pp, "description");
1904 snprintf(statusmsg, sizeof(statusmsg),
1905 "%s is now published", filename);
1906 ff_amf_write_string(&pp, statusmsg);
1907 ff_amf_write_field_name(&pp, "details");
1908 ff_amf_write_string(&pp, filename);
1909 ff_amf_write_object_end(&pp);
1911 spkt.size = pp - spkt.data;
1912 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1913 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1914 ff_rtmp_packet_destroy(&spkt);
1919 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1921 RTMPContext *rt = s->priv_data;
1927 const uint8_t *p = pkt->data;
1929 RTMPPacket spkt = { 0 };
1933 bytestream2_init(&gbc, p, pkt->size);
1934 if (ff_amf_read_string(&gbc, command, sizeof(command),
1936 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1937 return AVERROR_INVALIDDATA;
1940 ret = ff_amf_read_number(&gbc, &seqnum);
1943 ret = ff_amf_read_null(&gbc);
1946 if (!strcmp(command, "FCPublish") ||
1947 !strcmp(command, "publish")) {
1948 ret = ff_amf_read_string(&gbc, filename,
1949 sizeof(filename), &stringlen);
1951 if (ret == AVERROR(EINVAL))
1952 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1954 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1959 pchar = strrchr(s->filename, '/');
1961 av_log(s, AV_LOG_WARNING,
1962 "Unable to find / in url %s, bad format\n",
1964 pchar = s->filename;
1967 if (strcmp(pchar, filename))
1968 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1969 " %s\n", filename, pchar);
1971 rt->state = STATE_RECEIVING;
1974 if (!strcmp(command, "FCPublish")) {
1975 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1977 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1978 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1982 ff_amf_write_string(&pp, "onFCPublish");
1983 } else if (!strcmp(command, "publish")) {
1984 ret = write_begin(s);
1988 // Send onStatus(NetStream.Publish.Start)
1989 return write_status(s, pkt, "NetStream.Publish.Start",
1991 } else if (!strcmp(command, "play")) {
1992 ret = write_begin(s);
1995 rt->state = STATE_SENDING;
1996 return write_status(s, pkt, "NetStream.Play.Start",
1999 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
2001 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
2002 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2006 ff_amf_write_string(&pp, "_result");
2007 ff_amf_write_number(&pp, seqnum);
2008 ff_amf_write_null(&pp);
2009 if (!strcmp(command, "createStream")) {
2011 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2012 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2013 ff_amf_write_number(&pp, rt->nb_streamid);
2014 /* By now we don't control which streams are removed in
2015 * deleteStream. There is no stream creation control
2016 * if a client creates more than 2^32 - 2 streams. */
2019 spkt.size = pp - spkt.data;
2020 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2021 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2022 ff_rtmp_packet_destroy(&spkt);
2027 * Read the AMF_NUMBER response ("_result") to a function call
2028 * (e.g. createStream()). This response should be made up of the AMF_STRING
2029 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2030 * successful response, we will return set the value to number (otherwise number
2031 * will not be changed).
2033 * @return 0 if reading the value succeeds, negative value otherwise
2035 static int read_number_result(RTMPPacket *pkt, double *number)
2037 // We only need to fit "_result" in this.
2038 uint8_t strbuffer[8];
2043 bytestream2_init(&gbc, pkt->data, pkt->size);
2045 // Value 1/4: "_result" as AMF_STRING
2046 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2047 return AVERROR_INVALIDDATA;
2048 if (strcmp(strbuffer, "_result"))
2049 return AVERROR_INVALIDDATA;
2050 // Value 2/4: The callee reference number
2051 if (ff_amf_read_number(&gbc, &numbuffer))
2052 return AVERROR_INVALIDDATA;
2054 if (ff_amf_read_null(&gbc))
2055 return AVERROR_INVALIDDATA;
2056 // Value 4/4: The response as AMF_NUMBER
2057 if (ff_amf_read_number(&gbc, &numbuffer))
2058 return AVERROR_INVALIDDATA;
2060 *number = numbuffer;
2065 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2067 RTMPContext *rt = s->priv_data;
2068 char *tracked_method = NULL;
2071 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2074 if (!tracked_method) {
2075 /* Ignore this reply when the current method is not tracked. */
2079 if (!strcmp(tracked_method, "connect")) {
2080 if (!rt->is_input) {
2081 if ((ret = gen_release_stream(s, rt)) < 0)
2084 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2087 if ((ret = gen_server_bw(s, rt)) < 0)
2091 if ((ret = gen_create_stream(s, rt)) < 0)
2095 /* Send the FCSubscribe command when the name of live
2096 * stream is defined by the user or if it's a live stream. */
2097 if (rt->subscribe) {
2098 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2100 } else if (rt->live == -1) {
2101 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2105 } else if (!strcmp(tracked_method, "createStream")) {
2107 if (read_number_result(pkt, &stream_id)) {
2108 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2110 rt->stream_id = stream_id;
2113 if (!rt->is_input) {
2114 if ((ret = gen_publish(s, rt)) < 0)
2117 if (rt->live != -1) {
2118 if ((ret = gen_get_stream_length(s, rt)) < 0)
2121 if ((ret = gen_play(s, rt)) < 0)
2123 if ((ret = gen_buffer_time(s, rt)) < 0)
2126 } else if (!strcmp(tracked_method, "getStreamLength")) {
2127 if (read_number_result(pkt, &rt->duration)) {
2128 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2133 av_free(tracked_method);
2137 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2139 RTMPContext *rt = s->priv_data;
2140 const uint8_t *data_end = pkt->data + pkt->size;
2141 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2142 uint8_t tmpstr[256];
2145 for (i = 0; i < 2; i++) {
2146 t = ff_amf_tag_size(ptr, data_end);
2152 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2153 if (!t && !strcmp(tmpstr, "error")) {
2154 t = ff_amf_get_field_value(ptr, data_end,
2155 "description", tmpstr, sizeof(tmpstr));
2156 if (t || !tmpstr[0])
2157 t = ff_amf_get_field_value(ptr, data_end, "code",
2158 tmpstr, sizeof(tmpstr));
2160 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2164 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2165 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2166 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2167 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2168 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2169 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2174 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2176 RTMPContext *rt = s->priv_data;
2179 //TODO: check for the messages sent for wrong state?
2180 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2181 if ((ret = handle_invoke_error(s, pkt)) < 0)
2183 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2184 if ((ret = handle_invoke_result(s, pkt)) < 0)
2186 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2187 if ((ret = handle_invoke_status(s, pkt)) < 0)
2189 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2190 if ((ret = gen_check_bw(s, rt)) < 0)
2192 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2193 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2194 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2195 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2196 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2197 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2198 if ((ret = send_invoke_response(s, pkt)) < 0)
2205 static int update_offset(RTMPContext *rt, int size)
2209 // generate packet header and put data into buffer for FLV demuxer
2210 if (rt->flv_off < rt->flv_size) {
2211 // There is old unread data in the buffer, thus append at the end
2212 old_flv_size = rt->flv_size;
2213 rt->flv_size += size;
2215 // All data has been read, write the new data at the start of the buffer
2217 rt->flv_size = size;
2221 return old_flv_size;
2224 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2226 int old_flv_size, ret;
2228 const uint8_t *data = pkt->data + skip;
2229 const int size = pkt->size - skip;
2230 uint32_t ts = pkt->timestamp;
2232 if (pkt->type == RTMP_PT_AUDIO) {
2234 } else if (pkt->type == RTMP_PT_VIDEO) {
2238 old_flv_size = update_offset(rt, size + 15);
2240 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2241 rt->flv_size = rt->flv_off = 0;
2244 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2245 bytestream2_skip_p(&pbc, old_flv_size);
2246 bytestream2_put_byte(&pbc, pkt->type);
2247 bytestream2_put_be24(&pbc, size);
2248 bytestream2_put_be24(&pbc, ts);
2249 bytestream2_put_byte(&pbc, ts >> 24);
2250 bytestream2_put_be24(&pbc, 0);
2251 bytestream2_put_buffer(&pbc, data, size);
2252 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2257 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2259 RTMPContext *rt = s->priv_data;
2260 uint8_t commandbuffer[64];
2261 char statusmsg[128];
2262 int stringlen, ret, skip = 0;
2265 bytestream2_init(&gbc, pkt->data, pkt->size);
2266 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2268 return AVERROR_INVALIDDATA;
2270 if (!strcmp(commandbuffer, "onMetaData")) {
2271 // metadata properties should be stored in a mixed array
2272 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2273 // We have found a metaData Array so flv can determine the streams
2275 rt->received_metadata = 1;
2276 // skip 32-bit max array index
2277 bytestream2_skip(&gbc, 4);
2278 while (bytestream2_get_bytes_left(&gbc) > 3) {
2279 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2281 return AVERROR_INVALIDDATA;
2282 // We do not care about the content of the property (yet).
2283 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2285 return AVERROR_INVALIDDATA;
2286 bytestream2_skip(&gbc, stringlen);
2288 // The presence of the following properties indicates that the
2289 // respective streams are present.
2290 if (!strcmp(statusmsg, "videocodecid")) {
2293 if (!strcmp(statusmsg, "audiocodecid")) {
2297 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2298 return AVERROR_INVALIDDATA;
2302 // Skip the @setDataFrame string and validate it is a notification
2303 if (!strcmp(commandbuffer, "@setDataFrame")) {
2304 skip = gbc.buffer - pkt->data;
2305 ret = ff_amf_read_string(&gbc, statusmsg,
2306 sizeof(statusmsg), &stringlen);
2308 return AVERROR_INVALIDDATA;
2311 return append_flv_data(rt, pkt, skip);
2315 * Parse received packet and possibly perform some action depending on
2316 * the packet contents.
2317 * @return 0 for no errors, negative values for serious errors which prevent
2318 * further communications, positive values for uncritical errors
2320 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2325 ff_rtmp_packet_dump(s, pkt);
2328 switch (pkt->type) {
2329 case RTMP_PT_BYTES_READ:
2330 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2332 case RTMP_PT_CHUNK_SIZE:
2333 if ((ret = handle_chunk_size(s, pkt)) < 0)
2337 if ((ret = handle_ping(s, pkt)) < 0)
2340 case RTMP_PT_CLIENT_BW:
2341 if ((ret = handle_client_bw(s, pkt)) < 0)
2344 case RTMP_PT_SERVER_BW:
2345 if ((ret = handle_server_bw(s, pkt)) < 0)
2348 case RTMP_PT_INVOKE:
2349 if ((ret = handle_invoke(s, pkt)) < 0)
2354 case RTMP_PT_METADATA:
2355 case RTMP_PT_NOTIFY:
2356 /* Audio, Video and Metadata packets are parsed in get_packet() */
2359 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2365 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2367 int ret, old_flv_size, type;
2368 const uint8_t *next;
2371 uint32_t ts, cts, pts = 0;
2373 old_flv_size = update_offset(rt, pkt->size);
2375 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2376 rt->flv_size = rt->flv_off = 0;
2381 p = rt->flv_data + old_flv_size;
2383 /* copy data while rewriting timestamps */
2384 ts = pkt->timestamp;
2386 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2387 type = bytestream_get_byte(&next);
2388 size = bytestream_get_be24(&next);
2389 cts = bytestream_get_be24(&next);
2390 cts |= bytestream_get_byte(&next) << 24;
2395 if (size + 3 + 4 > pkt->data + pkt->size - next)
2397 bytestream_put_byte(&p, type);
2398 bytestream_put_be24(&p, size);
2399 bytestream_put_be24(&p, ts);
2400 bytestream_put_byte(&p, ts >> 24);
2401 memcpy(p, next, size + 3 + 4);
2403 bytestream_put_be32(&p, size + RTMP_HEADER);
2404 next += size + 3 + 4;
2406 if (p != rt->flv_data + rt->flv_size) {
2407 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2408 "RTMP_PT_METADATA packet\n");
2409 rt->flv_size = p - rt->flv_data;
2416 * Interact with the server by receiving and sending RTMP packets until
2417 * there is some significant data (media data or expected status notification).
2419 * @param s reading context
2420 * @param for_header non-zero value tells function to work until it
2421 * gets notification from the server that playing has been started,
2422 * otherwise function will work until some media data is received (or
2424 * @return 0 for successful operation, negative value in case of error
2426 static int get_packet(URLContext *s, int for_header)
2428 RTMPContext *rt = s->priv_data;
2431 if (rt->state == STATE_STOPPED)
2435 RTMPPacket rpkt = { 0 };
2436 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2437 rt->in_chunk_size, &rt->prev_pkt[0],
2438 &rt->nb_prev_pkt[0])) <= 0) {
2440 return AVERROR(EAGAIN);
2442 return AVERROR(EIO);
2446 // Track timestamp for later use
2447 rt->last_timestamp = rpkt.timestamp;
2449 rt->bytes_read += ret;
2450 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2451 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2452 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2454 rt->last_bytes_read = rt->bytes_read;
2457 ret = rtmp_parse_result(s, rt, &rpkt);
2459 // At this point we must check if we are in the seek state and continue
2460 // with the next packet. handle_invoke will get us out of this state
2461 // when the right message is encountered
2462 if (rt->state == STATE_SEEKING) {
2463 ff_rtmp_packet_destroy(&rpkt);
2464 // We continue, let the natural flow of things happen:
2465 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2469 if (ret < 0) {//serious error in current packet
2470 ff_rtmp_packet_destroy(&rpkt);
2473 if (rt->do_reconnect && for_header) {
2474 ff_rtmp_packet_destroy(&rpkt);
2477 if (rt->state == STATE_STOPPED) {
2478 ff_rtmp_packet_destroy(&rpkt);
2481 if (for_header && (rt->state == STATE_PLAYING ||
2482 rt->state == STATE_PUBLISHING ||
2483 rt->state == STATE_SENDING ||
2484 rt->state == STATE_RECEIVING)) {
2485 ff_rtmp_packet_destroy(&rpkt);
2488 if (!rpkt.size || !rt->is_input) {
2489 ff_rtmp_packet_destroy(&rpkt);
2492 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2493 ret = append_flv_data(rt, &rpkt, 0);
2494 ff_rtmp_packet_destroy(&rpkt);
2496 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2497 ret = handle_notify(s, &rpkt);
2498 ff_rtmp_packet_destroy(&rpkt);
2500 } else if (rpkt.type == RTMP_PT_METADATA) {
2501 ret = handle_metadata(rt, &rpkt);
2502 ff_rtmp_packet_destroy(&rpkt);
2505 ff_rtmp_packet_destroy(&rpkt);
2509 static int rtmp_close(URLContext *h)
2511 RTMPContext *rt = h->priv_data;
2514 if (!rt->is_input) {
2515 rt->flv_data = NULL;
2516 if (rt->out_pkt.size)
2517 ff_rtmp_packet_destroy(&rt->out_pkt);
2518 if (rt->state > STATE_FCPUBLISH)
2519 ret = gen_fcunpublish_stream(h, rt);
2521 if (rt->state > STATE_HANDSHAKED)
2522 ret = gen_delete_stream(h, rt);
2523 for (i = 0; i < 2; i++) {
2524 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2525 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2526 av_freep(&rt->prev_pkt[i]);
2529 free_tracked_methods(rt);
2530 av_freep(&rt->flv_data);
2531 ffurl_close(rt->stream);
2536 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2537 * demuxer about the duration of the stream.
2539 * This should only be done if there was no real onMetadata packet sent by the
2540 * server at the start of the stream and if we were able to retrieve a valid
2541 * duration via a getStreamLength call.
2543 * @return 0 for successful operation, negative value in case of error
2545 static int inject_fake_duration_metadata(RTMPContext *rt)
2547 // We need to insert the metadata packet directly after the FLV
2548 // header, i.e. we need to move all other already read data by the
2549 // size of our fake metadata packet.
2552 // Keep old flv_data pointer
2553 uint8_t* old_flv_data = rt->flv_data;
2554 // Allocate a new flv_data pointer with enough space for the additional package
2555 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2556 rt->flv_data = old_flv_data;
2557 return AVERROR(ENOMEM);
2561 memcpy(rt->flv_data, old_flv_data, 13);
2562 // Copy remaining packets
2563 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2564 // Increase the size by the injected packet
2566 // Delete the old FLV data
2567 av_freep(&old_flv_data);
2569 p = rt->flv_data + 13;
2570 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2571 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2572 bytestream_put_be24(&p, 0); // timestamp
2573 bytestream_put_be32(&p, 0); // reserved
2575 // first event name as a string
2576 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2577 // "onMetaData" as AMF string
2578 bytestream_put_be16(&p, 10);
2579 bytestream_put_buffer(&p, "onMetaData", 10);
2581 // mixed array (hash) with size and string/type/data tuples
2582 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2583 bytestream_put_be32(&p, 1); // metadata_count
2585 // "duration" as AMF string
2586 bytestream_put_be16(&p, 8);
2587 bytestream_put_buffer(&p, "duration", 8);
2588 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2589 bytestream_put_be64(&p, av_double2int(rt->duration));
2592 bytestream_put_be16(&p, 0); // Empty string
2593 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2594 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2600 * Open RTMP connection and verify that the stream can be played.
2602 * URL syntax: rtmp://server[:port][/app][/playpath]
2603 * where 'app' is first one or two directories in the path
2604 * (e.g. /ondemand/, /flash/live/, etc.)
2605 * and 'playpath' is a file name (the rest of the path,
2606 * may be prefixed with "mp4:")
2608 static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2610 RTMPContext *rt = s->priv_data;
2611 char proto[8], hostname[256], path[1024], auth[100], *fname;
2612 char *old_app, *qmark, *n, fname_buffer[1024];
2617 if (rt->listen_timeout > 0)
2620 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2622 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2623 hostname, sizeof(hostname), &port,
2624 path, sizeof(path), s->filename);
2626 n = strchr(path, ' ');
2628 av_log(s, AV_LOG_WARNING,
2629 "Detected librtmp style URL parameters, these aren't supported "
2630 "by the libavformat internal RTMP handler currently enabled. "
2631 "See the documentation for the correct way to pass parameters.\n");
2632 *n = '\0'; // Trim not supported part
2636 char *ptr = strchr(auth, ':');
2639 av_strlcpy(rt->username, auth, sizeof(rt->username));
2640 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2644 if (rt->listen && strcmp(proto, "rtmp")) {
2645 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2647 return AVERROR(EINVAL);
2649 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2650 if (!strcmp(proto, "rtmpts"))
2651 av_dict_set(opts, "ffrtmphttp_tls", "1", 1);
2653 /* open the http tunneling connection */
2654 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2655 } else if (!strcmp(proto, "rtmps")) {
2656 /* open the tls connection */
2658 port = RTMPS_DEFAULT_PORT;
2659 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2660 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2661 if (!strcmp(proto, "rtmpte"))
2662 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2664 /* open the encrypted connection */
2665 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2668 /* open the tcp connection */
2670 port = RTMP_DEFAULT_PORT;
2672 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2673 "?listen&listen_timeout=%d",
2674 rt->listen_timeout * 1000);
2676 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2680 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2681 &s->interrupt_callback, opts,
2682 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2683 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2687 if (rt->swfverify) {
2688 if ((ret = rtmp_calc_swfhash(s)) < 0)
2692 rt->state = STATE_START;
2693 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2695 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2698 rt->out_chunk_size = 128;
2699 rt->in_chunk_size = 128; // Probably overwritten later
2700 rt->state = STATE_HANDSHAKED;
2702 // Keep the application name when it has been defined by the user.
2705 rt->app = av_malloc(APP_MAX_LENGTH);
2707 ret = AVERROR(ENOMEM);
2711 //extract "app" part from path
2712 qmark = strchr(path, '?');
2713 if (qmark && strstr(qmark, "slist=")) {
2715 // After slist we have the playpath, the full path is used as app
2716 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2717 fname = strstr(path, "slist=") + 6;
2718 // Strip any further query parameters from fname
2719 amp = strchr(fname, '&');
2721 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2722 sizeof(fname_buffer)));
2723 fname = fname_buffer;
2725 } else if (!strncmp(path, "/ondemand/", 10)) {
2727 memcpy(rt->app, "ondemand", 9);
2729 char *next = *path ? path + 1 : path;
2730 char *p = strchr(next, '/');
2733 // If name of application has been defined by the user, assume that
2734 // playpath is provided in the URL
2738 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2741 // make sure we do not mismatch a playpath for an application instance
2742 char *c = strchr(p + 1, ':');
2743 fname = strchr(p + 1, '/');
2744 if (!fname || (c && c < fname)) {
2746 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2749 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2755 // The name of application has been defined by the user, override it.
2756 if (strlen(old_app) >= APP_MAX_LENGTH) {
2757 ret = AVERROR(EINVAL);
2764 if (!rt->playpath) {
2765 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2766 if (!rt->playpath) {
2767 ret = AVERROR(ENOMEM);
2772 int len = strlen(fname);
2773 if (!strchr(fname, ':') && len >= 4 &&
2774 (!strcmp(fname + len - 4, ".f4v") ||
2775 !strcmp(fname + len - 4, ".mp4"))) {
2776 memcpy(rt->playpath, "mp4:", 5);
2778 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2779 fname[len - 4] = '\0';
2780 rt->playpath[0] = 0;
2782 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2784 rt->playpath[0] = '\0';
2789 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2791 ret = AVERROR(ENOMEM);
2794 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2795 port, "/%s", rt->app);
2798 if (!rt->flashver) {
2799 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2800 if (!rt->flashver) {
2801 ret = AVERROR(ENOMEM);
2805 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2806 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2807 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2809 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2810 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2814 rt->client_report_size = 1048576;
2818 rt->received_metadata = 0;
2819 rt->last_bytes_read = 0;
2820 rt->server_bw = 2500000;
2823 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2824 proto, path, rt->app, rt->playpath);
2826 if ((ret = gen_connect(s, rt)) < 0)
2829 if ((ret = read_connect(s, s->priv_data)) < 0)
2834 ret = get_packet(s, 1);
2835 } while (ret == AVERROR(EAGAIN));
2839 if (rt->do_reconnect) {
2841 ffurl_close(rt->stream);
2843 rt->do_reconnect = 0;
2845 for (i = 0; i < 2; i++)
2846 memset(rt->prev_pkt[i], 0,
2847 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2848 free_tracked_methods(rt);
2853 // generate FLV header for demuxer
2855 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2858 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2860 // Read packets until we reach the first A/V packet or read metadata.
2861 // If there was a metadata package in front of the A/V packets, we can
2862 // build the FLV header from this. If we do not receive any metadata,
2863 // the FLV decoder will allocate the needed streams when their first
2864 // audio or video packet arrives.
2865 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2866 if ((ret = get_packet(s, 0)) < 0)
2870 // Either after we have read the metadata or (if there is none) the
2871 // first packet of an A/V stream, we have a better knowledge about the
2872 // streams, so set the FLV header accordingly.
2873 if (rt->has_audio) {
2874 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2876 if (rt->has_video) {
2877 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2880 // If we received the first packet of an A/V stream and no metadata but
2881 // the server returned a valid duration, create a fake metadata packet
2882 // to inform the FLV decoder about the duration.
2883 if (!rt->received_metadata && rt->duration > 0) {
2884 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2889 rt->flv_data = NULL;
2891 rt->skip_bytes = 13;
2894 s->max_packet_size = rt->stream->max_packet_size;
2904 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2906 RTMPContext *rt = s->priv_data;
2907 int orig_size = size;
2911 int data_left = rt->flv_size - rt->flv_off;
2913 if (data_left >= size) {
2914 memcpy(buf, rt->flv_data + rt->flv_off, size);
2915 rt->flv_off += size;
2918 if (data_left > 0) {
2919 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2922 rt->flv_off = rt->flv_size;
2925 if ((ret = get_packet(s, 0)) < 0)
2931 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2934 RTMPContext *rt = s->priv_data;
2936 av_log(s, AV_LOG_DEBUG,
2937 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2938 stream_index, timestamp, flags);
2939 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2940 av_log(s, AV_LOG_ERROR,
2941 "Unable to send seek command on stream index %d at timestamp "
2942 "%"PRId64" with flags %08x\n",
2943 stream_index, timestamp, flags);
2946 rt->flv_off = rt->flv_size;
2947 rt->state = STATE_SEEKING;
2951 static int rtmp_pause(URLContext *s, int pause)
2953 RTMPContext *rt = s->priv_data;
2955 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2956 rt->last_timestamp);
2957 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2958 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2959 rt->last_timestamp);
2965 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2967 RTMPContext *rt = s->priv_data;
2968 int size_temp = size;
2969 int pktsize, pkttype, copy;
2971 const uint8_t *buf_temp = buf;
2976 if (rt->skip_bytes) {
2977 int skip = FFMIN(rt->skip_bytes, size_temp);
2980 rt->skip_bytes -= skip;
2984 if (rt->flv_header_bytes < RTMP_HEADER) {
2985 const uint8_t *header = rt->flv_header;
2986 int channel = RTMP_AUDIO_CHANNEL;
2988 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2989 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2990 rt->flv_header_bytes += copy;
2992 if (rt->flv_header_bytes < RTMP_HEADER)
2995 pkttype = bytestream_get_byte(&header);
2996 pktsize = bytestream_get_be24(&header);
2997 ts = bytestream_get_be24(&header);
2998 ts |= bytestream_get_byte(&header) << 24;
2999 bytestream_get_be24(&header);
3000 rt->flv_size = pktsize;
3002 if (pkttype == RTMP_PT_VIDEO)
3003 channel = RTMP_VIDEO_CHANNEL;
3005 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
3006 pkttype == RTMP_PT_NOTIFY) {
3007 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
3008 &rt->nb_prev_pkt[1],
3011 // Force sending a full 12 bytes header by clearing the
3012 // channel id, to make it not match a potential earlier
3013 // packet in the same channel.
3014 rt->prev_pkt[1][channel].channel_id = 0;
3017 //this can be a big packet, it's better to send it right here
3018 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3019 pkttype, ts, pktsize)) < 0)
3022 rt->out_pkt.extra = rt->stream_id;
3023 rt->flv_data = rt->out_pkt.data;
3026 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3027 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3028 rt->flv_off += copy;
3031 if (rt->flv_off == rt->flv_size) {
3034 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3035 // For onMetaData and |RtmpSampleAccess packets, we want
3036 // @setDataFrame prepended to the packet before it gets sent.
3037 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3039 uint8_t commandbuffer[64];
3043 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3044 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3046 if (!strcmp(commandbuffer, "onMetaData") ||
3047 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3049 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3050 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3053 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3054 rt->out_pkt.size += 16;
3055 ptr = rt->out_pkt.data;
3056 ff_amf_write_string(&ptr, "@setDataFrame");
3061 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3065 rt->flv_header_bytes = 0;
3066 rt->flv_nb_packets++;
3068 } while (buf_temp - buf < size);
3070 if (rt->flv_nb_packets < rt->flush_interval)
3072 rt->flv_nb_packets = 0;
3074 /* set stream into nonblocking mode */
3075 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3077 /* try to read one byte from the stream */
3078 ret = ffurl_read(rt->stream, &c, 1);
3080 /* switch the stream back into blocking mode */
3081 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3083 if (ret == AVERROR(EAGAIN)) {
3084 /* no incoming data to handle */
3086 } else if (ret < 0) {
3088 } else if (ret == 1) {
3089 RTMPPacket rpkt = { 0 };
3091 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3094 &rt->nb_prev_pkt[0], c)) <= 0)
3097 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3100 ff_rtmp_packet_destroy(&rpkt);
3106 #define OFFSET(x) offsetof(RTMPContext, x)
3107 #define DEC AV_OPT_FLAG_DECODING_PARAM
3108 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3110 static const AVOption rtmp_options[] = {
3111 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3112 {"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},
3113 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3114 {"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},
3115 {"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},
3116 {"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"},
3117 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3118 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3119 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3120 {"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},
3121 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3122 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3123 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3124 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3125 {"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},
3126 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3127 {"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},
3128 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3129 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3130 {"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" },
3134 #define RTMP_PROTOCOL(flavor) \
3135 static const AVClass flavor##_class = { \
3136 .class_name = #flavor, \
3137 .item_name = av_default_item_name, \
3138 .option = rtmp_options, \
3139 .version = LIBAVUTIL_VERSION_INT, \
3142 const URLProtocol ff_##flavor##_protocol = { \
3144 .url_open2 = rtmp_open, \
3145 .url_read = rtmp_read, \
3146 .url_read_seek = rtmp_seek, \
3147 .url_read_pause = rtmp_pause, \
3148 .url_write = rtmp_write, \
3149 .url_close = rtmp_close, \
3150 .priv_data_size = sizeof(RTMPContext), \
3151 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3152 .priv_data_class= &flavor##_class, \
3157 RTMP_PROTOCOL(rtmpe)
3158 RTMP_PROTOCOL(rtmps)
3159 RTMP_PROTOCOL(rtmpt)
3160 RTMP_PROTOCOL(rtmpte)
3161 RTMP_PROTOCOL(rtmpts)