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);
344 if (rt->swfurl || rt->swfverify) {
345 ff_amf_write_field_name(&p, "swfUrl");
347 ff_amf_write_string(&p, rt->swfurl);
349 ff_amf_write_string(&p, rt->swfverify);
352 ff_amf_write_field_name(&p, "tcUrl");
353 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
355 ff_amf_write_field_name(&p, "fpad");
356 ff_amf_write_bool(&p, 0);
357 ff_amf_write_field_name(&p, "capabilities");
358 ff_amf_write_number(&p, 15.0);
360 /* Tell the server we support all the audio codecs except
361 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
362 * which are unused in the RTMP protocol implementation. */
363 ff_amf_write_field_name(&p, "audioCodecs");
364 ff_amf_write_number(&p, 4071.0);
365 ff_amf_write_field_name(&p, "videoCodecs");
366 ff_amf_write_number(&p, 252.0);
367 ff_amf_write_field_name(&p, "videoFunction");
368 ff_amf_write_number(&p, 1.0);
371 ff_amf_write_field_name(&p, "pageUrl");
372 ff_amf_write_string(&p, rt->pageurl);
375 ff_amf_write_object_end(&p);
378 char *param = rt->conn;
380 // Write arbitrary AMF data to the Connect message.
383 param += strspn(param, " ");
386 sep = strchr(param, ' ');
389 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
390 // Invalid AMF parameter.
391 ff_rtmp_packet_destroy(&pkt);
402 pkt.size = p - pkt.data;
404 return rtmp_send_packet(rt, &pkt, 1);
408 #define RTMP_CTRL_ABORT_MESSAGE (2)
410 static int read_connect(URLContext *s, RTMPContext *rt)
412 RTMPPacket pkt = { 0 };
422 // handle RTMP Protocol Control Messages
424 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
425 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
428 ff_rtmp_packet_dump(s, &pkt);
430 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
431 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
432 ff_rtmp_packet_destroy(&pkt);
435 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
436 av_log(s, AV_LOG_ERROR, "received abort message\n");
437 ff_rtmp_packet_destroy(&pkt);
438 return AVERROR_UNKNOWN;
439 } else if (pkt.type == RTMP_PT_BYTES_READ) {
440 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
441 } else if (pkt.type == RTMP_PT_SERVER_BW) {
442 if ((ret = handle_server_bw(s, &pkt)) < 0) {
443 ff_rtmp_packet_destroy(&pkt);
446 } else if (pkt.type == RTMP_PT_CLIENT_BW) {
447 if ((ret = handle_client_bw(s, &pkt)) < 0) {
448 ff_rtmp_packet_destroy(&pkt);
451 } else if (pkt.type == RTMP_PT_INVOKE) {
452 // received RTMP Command Message
455 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
457 ff_rtmp_packet_destroy(&pkt);
461 bytestream2_init(&gbc, cp, pkt.size);
462 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
463 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
464 ff_rtmp_packet_destroy(&pkt);
465 return AVERROR_INVALIDDATA;
467 if (strcmp(command, "connect")) {
468 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
469 ff_rtmp_packet_destroy(&pkt);
470 return AVERROR_INVALIDDATA;
472 ret = ff_amf_read_number(&gbc, &seqnum);
474 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
475 /* Here one could parse an AMF Object with data as flashVers and others. */
476 ret = ff_amf_get_field_value(gbc.buffer,
477 gbc.buffer + bytestream2_get_bytes_left(&gbc),
478 "app", tmpstr, sizeof(tmpstr));
480 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
481 if (!ret && strcmp(tmpstr, rt->app))
482 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
484 ff_rtmp_packet_destroy(&pkt);
486 // Send Window Acknowledgement Size (as defined in specification)
487 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
488 RTMP_PT_SERVER_BW, 0, 4)) < 0)
491 bytestream_put_be32(&p, rt->server_bw);
492 pkt.size = p - pkt.data;
493 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
494 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
495 ff_rtmp_packet_destroy(&pkt);
498 // Send Peer Bandwidth
499 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
500 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
503 bytestream_put_be32(&p, rt->server_bw);
504 bytestream_put_byte(&p, 2); // dynamic
505 pkt.size = p - pkt.data;
506 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
507 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
508 ff_rtmp_packet_destroy(&pkt);
513 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
514 RTMP_PT_PING, 0, 6)) < 0)
518 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
519 bytestream_put_be32(&p, 0);
520 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
521 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
522 ff_rtmp_packet_destroy(&pkt);
527 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
528 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
532 bytestream_put_be32(&p, rt->out_chunk_size);
533 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
534 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
535 ff_rtmp_packet_destroy(&pkt);
539 // Send _result NetConnection.Connect.Success to connect
540 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
542 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
546 ff_amf_write_string(&p, "_result");
547 ff_amf_write_number(&p, seqnum);
549 ff_amf_write_object_start(&p);
550 ff_amf_write_field_name(&p, "fmsVer");
551 ff_amf_write_string(&p, "FMS/3,0,1,123");
552 ff_amf_write_field_name(&p, "capabilities");
553 ff_amf_write_number(&p, 31);
554 ff_amf_write_object_end(&p);
556 ff_amf_write_object_start(&p);
557 ff_amf_write_field_name(&p, "level");
558 ff_amf_write_string(&p, "status");
559 ff_amf_write_field_name(&p, "code");
560 ff_amf_write_string(&p, "NetConnection.Connect.Success");
561 ff_amf_write_field_name(&p, "description");
562 ff_amf_write_string(&p, "Connection succeeded.");
563 ff_amf_write_field_name(&p, "objectEncoding");
564 ff_amf_write_number(&p, 0);
565 ff_amf_write_object_end(&p);
567 pkt.size = p - pkt.data;
568 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
569 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
570 ff_rtmp_packet_destroy(&pkt);
574 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
575 RTMP_PT_INVOKE, 0, 30)) < 0)
578 ff_amf_write_string(&p, "onBWDone");
579 ff_amf_write_number(&p, 0);
580 ff_amf_write_null(&p);
581 ff_amf_write_number(&p, 8192);
582 pkt.size = p - pkt.data;
583 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
584 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
585 ff_rtmp_packet_destroy(&pkt);
591 * Generate 'releaseStream' call and send it to the server. It should make
592 * the server release some channel for media streams.
594 static int gen_release_stream(URLContext *s, RTMPContext *rt)
600 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
601 0, 29 + strlen(rt->playpath))) < 0)
604 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
606 ff_amf_write_string(&p, "releaseStream");
607 ff_amf_write_number(&p, ++rt->nb_invokes);
608 ff_amf_write_null(&p);
609 ff_amf_write_string(&p, rt->playpath);
611 return rtmp_send_packet(rt, &pkt, 1);
615 * Generate 'FCPublish' call and send it to the server. It should make
616 * the server prepare for receiving media streams.
618 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
624 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
625 0, 25 + strlen(rt->playpath))) < 0)
628 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
630 ff_amf_write_string(&p, "FCPublish");
631 ff_amf_write_number(&p, ++rt->nb_invokes);
632 ff_amf_write_null(&p);
633 ff_amf_write_string(&p, rt->playpath);
635 return rtmp_send_packet(rt, &pkt, 1);
639 * Generate 'FCUnpublish' call and send it to the server. It should make
640 * the server destroy stream.
642 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
648 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
649 0, 27 + strlen(rt->playpath))) < 0)
652 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
654 ff_amf_write_string(&p, "FCUnpublish");
655 ff_amf_write_number(&p, ++rt->nb_invokes);
656 ff_amf_write_null(&p);
657 ff_amf_write_string(&p, rt->playpath);
659 return rtmp_send_packet(rt, &pkt, 0);
663 * Generate 'createStream' call and send it to the server. It should make
664 * the server allocate some channel for media streams.
666 static int gen_create_stream(URLContext *s, RTMPContext *rt)
672 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
674 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
679 ff_amf_write_string(&p, "createStream");
680 ff_amf_write_number(&p, ++rt->nb_invokes);
681 ff_amf_write_null(&p);
683 return rtmp_send_packet(rt, &pkt, 1);
688 * Generate 'deleteStream' call and send it to the server. It should make
689 * the server remove some channel for media streams.
691 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
697 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
699 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
704 ff_amf_write_string(&p, "deleteStream");
705 ff_amf_write_number(&p, ++rt->nb_invokes);
706 ff_amf_write_null(&p);
707 ff_amf_write_number(&p, rt->stream_id);
709 return rtmp_send_packet(rt, &pkt, 0);
713 * Generate 'getStreamLength' call and send it to the server. If the server
714 * knows the duration of the selected stream, it will reply with the duration
717 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
723 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
724 0, 31 + strlen(rt->playpath))) < 0)
728 ff_amf_write_string(&p, "getStreamLength");
729 ff_amf_write_number(&p, ++rt->nb_invokes);
730 ff_amf_write_null(&p);
731 ff_amf_write_string(&p, rt->playpath);
733 return rtmp_send_packet(rt, &pkt, 1);
737 * Generate client buffer time and send it to the server.
739 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
745 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
750 bytestream_put_be16(&p, 3);
751 bytestream_put_be32(&p, rt->stream_id);
752 bytestream_put_be32(&p, rt->client_buffer_time);
754 return rtmp_send_packet(rt, &pkt, 0);
758 * Generate 'play' call and send it to the server, then ping the server
759 * to start actual playing.
761 static int gen_play(URLContext *s, RTMPContext *rt)
767 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
769 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
770 0, 29 + strlen(rt->playpath))) < 0)
773 pkt.extra = rt->stream_id;
776 ff_amf_write_string(&p, "play");
777 ff_amf_write_number(&p, ++rt->nb_invokes);
778 ff_amf_write_null(&p);
779 ff_amf_write_string(&p, rt->playpath);
780 ff_amf_write_number(&p, rt->live * 1000);
782 return rtmp_send_packet(rt, &pkt, 1);
785 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
791 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
794 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
797 pkt.extra = rt->stream_id;
800 ff_amf_write_string(&p, "seek");
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_number(&p, timestamp); //where we want to jump
805 return rtmp_send_packet(rt, &pkt, 1);
809 * Generate a pause packet that either pauses or unpauses the current stream.
811 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
817 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
820 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
823 pkt.extra = rt->stream_id;
826 ff_amf_write_string(&p, "pause");
827 ff_amf_write_number(&p, 0); //no tracking back responses
828 ff_amf_write_null(&p); //as usual, the first null param
829 ff_amf_write_bool(&p, pause); // pause or unpause
830 ff_amf_write_number(&p, timestamp); //where we pause the stream
832 return rtmp_send_packet(rt, &pkt, 1);
836 * Generate 'publish' call and send it to the server.
838 static int gen_publish(URLContext *s, RTMPContext *rt)
844 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
846 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
847 0, 30 + strlen(rt->playpath))) < 0)
850 pkt.extra = rt->stream_id;
853 ff_amf_write_string(&p, "publish");
854 ff_amf_write_number(&p, ++rt->nb_invokes);
855 ff_amf_write_null(&p);
856 ff_amf_write_string(&p, rt->playpath);
857 ff_amf_write_string(&p, "live");
859 return rtmp_send_packet(rt, &pkt, 1);
863 * Generate ping reply and send it to the server.
865 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
871 if (ppkt->size < 6) {
872 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
874 return AVERROR_INVALIDDATA;
877 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
878 ppkt->timestamp + 1, 6)) < 0)
882 bytestream_put_be16(&p, 7);
883 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
885 return rtmp_send_packet(rt, &pkt, 0);
889 * Generate SWF verification message and send it to the server.
891 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
897 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
898 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
903 bytestream_put_be16(&p, 27);
904 memcpy(p, rt->swfverification, 42);
906 return rtmp_send_packet(rt, &pkt, 0);
910 * Generate server bandwidth message and send it to the server.
912 static int gen_server_bw(URLContext *s, RTMPContext *rt)
918 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
923 bytestream_put_be32(&p, rt->server_bw);
925 return rtmp_send_packet(rt, &pkt, 0);
929 * Generate check bandwidth message and send it to the server.
931 static int gen_check_bw(URLContext *s, RTMPContext *rt)
937 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
942 ff_amf_write_string(&p, "_checkbw");
943 ff_amf_write_number(&p, ++rt->nb_invokes);
944 ff_amf_write_null(&p);
946 return rtmp_send_packet(rt, &pkt, 1);
950 * Generate report on bytes read so far and send it to the server.
952 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
958 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
963 bytestream_put_be32(&p, rt->bytes_read);
965 return rtmp_send_packet(rt, &pkt, 0);
968 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
969 const char *subscribe)
975 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
976 0, 27 + strlen(subscribe))) < 0)
980 ff_amf_write_string(&p, "FCSubscribe");
981 ff_amf_write_number(&p, ++rt->nb_invokes);
982 ff_amf_write_null(&p);
983 ff_amf_write_string(&p, subscribe);
985 return rtmp_send_packet(rt, &pkt, 1);
988 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
989 const uint8_t *key, int keylen, uint8_t *dst)
993 hmac = av_hmac_alloc(AV_HMAC_SHA256);
995 return AVERROR(ENOMEM);
997 av_hmac_init(hmac, key, keylen);
999 av_hmac_update(hmac, src, len);
1000 } else { //skip 32 bytes used for storing digest
1001 av_hmac_update(hmac, src, gap);
1002 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
1004 av_hmac_final(hmac, dst, 32);
1011 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1014 int i, digest_pos = 0;
1016 for (i = 0; i < 4; i++)
1017 digest_pos += buf[i + off];
1018 digest_pos = digest_pos % mod_val + add_val;
1024 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1025 * will be stored) into that packet.
1027 * @param buf handshake data (1536 bytes)
1028 * @param encrypted use an encrypted connection (RTMPE)
1029 * @return offset to the digest inside input data
1031 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1033 int ret, digest_pos;
1036 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1038 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1040 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1041 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1050 * Verify that the received server response has the expected digest value.
1052 * @param buf handshake data received from the server (1536 bytes)
1053 * @param off position to search digest offset from
1054 * @return 0 if digest is valid, digest position otherwise
1056 static int rtmp_validate_digest(uint8_t *buf, int off)
1059 int ret, digest_pos;
1061 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1063 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1064 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1069 if (!memcmp(digest, buf + digest_pos, 32))
1074 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1080 if (rt->swfhash_len != 32) {
1081 av_log(s, AV_LOG_ERROR,
1082 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1083 return AVERROR(EINVAL);
1086 p = &rt->swfverification[0];
1087 bytestream_put_byte(&p, 1);
1088 bytestream_put_byte(&p, 1);
1089 bytestream_put_be32(&p, rt->swfsize);
1090 bytestream_put_be32(&p, rt->swfsize);
1092 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1099 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1100 uint8_t **out_data, int64_t *out_size)
1102 z_stream zs = { 0 };
1107 zs.avail_in = in_size;
1108 zs.next_in = in_data;
1109 ret = inflateInit(&zs);
1111 return AVERROR_UNKNOWN;
1114 uint8_t tmp_buf[16384];
1116 zs.avail_out = sizeof(tmp_buf);
1117 zs.next_out = tmp_buf;
1119 ret = inflate(&zs, Z_NO_FLUSH);
1120 if (ret != Z_OK && ret != Z_STREAM_END) {
1121 ret = AVERROR_UNKNOWN;
1125 size = sizeof(tmp_buf) - zs.avail_out;
1126 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1127 ret = AVERROR(ENOMEM);
1132 memcpy(*out_data + *out_size, tmp_buf, size);
1134 } while (zs.avail_out == 0);
1142 static int rtmp_calc_swfhash(URLContext *s)
1144 RTMPContext *rt = s->priv_data;
1145 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1152 /* Get the SWF player file. */
1153 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1154 &s->interrupt_callback, NULL,
1155 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1156 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1160 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1165 if (!(in_data = av_malloc(in_size))) {
1166 ret = AVERROR(ENOMEM);
1170 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1174 ret = AVERROR_INVALIDDATA;
1178 if (!memcmp(in_data, "CWS", 3)) {
1181 /* Decompress the SWF player file using Zlib. */
1182 if (!(out_data = av_malloc(8))) {
1183 ret = AVERROR(ENOMEM);
1186 *in_data = 'F'; // magic stuff
1187 memcpy(out_data, in_data, 8);
1190 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1191 &out_data, &out_size)) < 0)
1196 av_log(s, AV_LOG_ERROR,
1197 "Zlib is required for decompressing the SWF player file.\n");
1198 ret = AVERROR(EINVAL);
1206 /* Compute the SHA256 hash of the SWF player file. */
1207 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1208 "Genuine Adobe Flash Player 001", 30,
1212 /* Set SWFVerification parameters. */
1213 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1214 rt->swfsize = swfsize;
1218 av_freep(&out_data);
1219 ffurl_close(stream);
1224 * Perform handshake with the server by means of exchanging pseudorandom data
1225 * signed with HMAC-SHA2 digest.
1227 * @return 0 if handshake succeeds, negative value otherwise
1229 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1232 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1233 3, // unencrypted data
1234 0, 0, 0, 0, // client uptime
1240 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1241 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1243 int server_pos, client_pos;
1244 uint8_t digest[32], signature[32];
1247 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1249 av_lfg_init(&rnd, 0xDEADC0DE);
1250 // generate handshake packet - 1536 bytes of pseudorandom data
1251 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1252 tosend[i] = av_lfg_get(&rnd) >> 24;
1254 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1255 /* When the client wants to use RTMPE, we have to change the command
1256 * byte to 0x06 which means to use encrypted data and we have to set
1257 * the flash version to at least 9.0.115.0. */
1264 /* Initialize the Diffie-Hellmann context and generate the public key
1265 * to send to the server. */
1266 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1270 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1274 if ((ret = ffurl_write(rt->stream, tosend,
1275 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1276 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1280 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1281 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1282 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1286 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1287 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1288 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1292 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1293 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1294 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1296 if (rt->is_input && serverdata[5] >= 3) {
1297 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1303 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1308 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1309 return AVERROR(EIO);
1313 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1314 * key are the last 32 bytes of the server handshake. */
1316 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1317 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1321 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1322 rtmp_server_key, sizeof(rtmp_server_key),
1327 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1328 0, digest, 32, signature);
1332 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1333 /* Compute the shared secret key sent by the server and initialize
1334 * the RC4 encryption. */
1335 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1336 tosend + 1, type)) < 0)
1339 /* Encrypt the signature received by the server. */
1340 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1343 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1344 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1345 return AVERROR(EIO);
1348 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1349 tosend[i] = av_lfg_get(&rnd) >> 24;
1350 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1351 rtmp_player_key, sizeof(rtmp_player_key),
1356 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1358 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1362 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1363 /* Encrypt the signature to be send to the server. */
1364 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1365 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1369 // write reply back to the server
1370 if ((ret = ffurl_write(rt->stream, tosend,
1371 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1374 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1375 /* Set RC4 keys for encryption and update the keystreams. */
1376 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1380 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1381 /* Compute the shared secret key sent by the server and initialize
1382 * the RC4 encryption. */
1383 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1384 tosend + 1, 1)) < 0)
1387 if (serverdata[0] == 9) {
1388 /* Encrypt the signature received by the server. */
1389 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1394 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1395 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1398 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1399 /* Set RC4 keys for encryption and update the keystreams. */
1400 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1408 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1409 uint32_t *second_int, char *arraydata,
1414 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1415 RTMP_HANDSHAKE_PACKET_SIZE);
1417 return AVERROR(EIO);
1418 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1419 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1420 " not following standard\n", (int)inoutsize);
1421 return AVERROR(EINVAL);
1424 *first_int = AV_RB32(arraydata);
1425 *second_int = AV_RB32(arraydata + 4);
1429 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1430 uint32_t second_int, char *arraydata, int size)
1434 AV_WB32(arraydata, first_int);
1435 AV_WB32(arraydata + 4, second_int);
1436 inoutsize = ffurl_write(rt->stream, arraydata,
1437 RTMP_HANDSHAKE_PACKET_SIZE);
1438 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1439 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1440 return AVERROR(EIO);
1447 * rtmp handshake server side
1449 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1451 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1453 uint32_t hs_my_epoch;
1454 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1455 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1462 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1463 if (inoutsize <= 0) {
1464 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1465 return AVERROR(EIO);
1468 if (buffer[0] != 3) {
1469 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1470 return AVERROR(EIO);
1472 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1473 av_log(s, AV_LOG_ERROR,
1474 "Unable to write answer - RTMP S0\n");
1475 return AVERROR(EIO);
1478 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1479 RTMP_HANDSHAKE_PACKET_SIZE);
1481 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1485 /* By now same epoch will be sent */
1486 hs_my_epoch = hs_epoch;
1487 /* Generate random */
1488 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1490 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1492 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1493 RTMP_HANDSHAKE_PACKET_SIZE);
1495 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1499 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1500 RTMP_HANDSHAKE_PACKET_SIZE);
1502 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1506 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1507 RTMP_HANDSHAKE_PACKET_SIZE);
1509 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1512 if (temp != hs_my_epoch)
1513 av_log(s, AV_LOG_WARNING,
1514 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1515 if (memcmp(buffer + 8, hs_s1 + 8,
1516 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1517 av_log(s, AV_LOG_WARNING,
1518 "Erroneous C2 Message random does not match up\n");
1523 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1525 RTMPContext *rt = s->priv_data;
1528 if (pkt->size < 4) {
1529 av_log(s, AV_LOG_ERROR,
1530 "Too short chunk size change packet (%d)\n",
1532 return AVERROR_INVALIDDATA;
1535 if (!rt->is_input) {
1536 /* Send the same chunk size change packet back to the server,
1537 * setting the outgoing chunk size to the same as the incoming one. */
1538 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1539 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1541 rt->out_chunk_size = AV_RB32(pkt->data);
1544 rt->in_chunk_size = AV_RB32(pkt->data);
1545 if (rt->in_chunk_size <= 0) {
1546 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1548 return AVERROR_INVALIDDATA;
1550 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1556 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1558 RTMPContext *rt = s->priv_data;
1561 if (pkt->size < 2) {
1562 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1564 return AVERROR_INVALIDDATA;
1567 t = AV_RB16(pkt->data);
1569 if ((ret = gen_pong(s, rt, pkt)) < 0)
1571 } else if (t == 26) {
1573 if ((ret = gen_swf_verification(s, rt)) < 0)
1576 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1583 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1585 RTMPContext *rt = s->priv_data;
1587 if (pkt->size < 4) {
1588 av_log(s, AV_LOG_ERROR,
1589 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1591 return AVERROR_INVALIDDATA;
1594 rt->client_report_size = AV_RB32(pkt->data);
1595 if (rt->client_report_size <= 0) {
1596 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1597 rt->client_report_size);
1598 return AVERROR_INVALIDDATA;
1601 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1602 rt->client_report_size >>= 1;
1607 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1609 RTMPContext *rt = s->priv_data;
1611 if (pkt->size < 4) {
1612 av_log(s, AV_LOG_ERROR,
1613 "Too short server bandwidth report packet (%d)\n",
1615 return AVERROR_INVALIDDATA;
1618 rt->server_bw = AV_RB32(pkt->data);
1619 if (rt->server_bw <= 0) {
1620 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1622 return AVERROR_INVALIDDATA;
1624 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1629 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1630 const char *opaque, const char *challenge)
1633 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1634 struct AVMD5 *md5 = av_md5_alloc();
1636 return AVERROR(ENOMEM);
1638 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1641 av_md5_update(md5, user, strlen(user));
1642 av_md5_update(md5, salt, strlen(salt));
1643 av_md5_update(md5, rt->password, strlen(rt->password));
1644 av_md5_final(md5, hash);
1645 av_base64_encode(hashstr, sizeof(hashstr), hash,
1648 av_md5_update(md5, hashstr, strlen(hashstr));
1650 av_md5_update(md5, opaque, strlen(opaque));
1652 av_md5_update(md5, challenge, strlen(challenge));
1653 av_md5_update(md5, challenge2, strlen(challenge2));
1654 av_md5_final(md5, hash);
1655 av_base64_encode(hashstr, sizeof(hashstr), hash,
1657 snprintf(rt->auth_params, sizeof(rt->auth_params),
1658 "?authmod=%s&user=%s&challenge=%s&response=%s",
1659 "adobe", user, challenge2, hashstr);
1661 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1662 "&opaque=%s", opaque);
1668 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1671 char hashstr1[33], hashstr2[33];
1672 const char *realm = "live";
1673 const char *method = "publish";
1674 const char *qop = "auth";
1675 const char *nc = "00000001";
1677 struct AVMD5 *md5 = av_md5_alloc();
1679 return AVERROR(ENOMEM);
1681 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1684 av_md5_update(md5, user, strlen(user));
1685 av_md5_update(md5, ":", 1);
1686 av_md5_update(md5, realm, strlen(realm));
1687 av_md5_update(md5, ":", 1);
1688 av_md5_update(md5, rt->password, strlen(rt->password));
1689 av_md5_final(md5, hash);
1690 ff_data_to_hex(hashstr1, hash, 16, 1);
1691 hashstr1[32] = '\0';
1694 av_md5_update(md5, method, strlen(method));
1695 av_md5_update(md5, ":/", 2);
1696 av_md5_update(md5, rt->app, strlen(rt->app));
1697 if (!strchr(rt->app, '/'))
1698 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1699 av_md5_final(md5, hash);
1700 ff_data_to_hex(hashstr2, hash, 16, 1);
1701 hashstr2[32] = '\0';
1704 av_md5_update(md5, hashstr1, strlen(hashstr1));
1705 av_md5_update(md5, ":", 1);
1707 av_md5_update(md5, nonce, strlen(nonce));
1708 av_md5_update(md5, ":", 1);
1709 av_md5_update(md5, nc, strlen(nc));
1710 av_md5_update(md5, ":", 1);
1711 av_md5_update(md5, cnonce, strlen(cnonce));
1712 av_md5_update(md5, ":", 1);
1713 av_md5_update(md5, qop, strlen(qop));
1714 av_md5_update(md5, ":", 1);
1715 av_md5_update(md5, hashstr2, strlen(hashstr2));
1716 av_md5_final(md5, hash);
1717 ff_data_to_hex(hashstr1, hash, 16, 1);
1719 snprintf(rt->auth_params, sizeof(rt->auth_params),
1720 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1721 "llnw", user, nonce, cnonce, nc, hashstr1);
1727 static int handle_connect_error(URLContext *s, const char *desc)
1729 RTMPContext *rt = s->priv_data;
1730 char buf[300], *ptr, authmod[15];
1732 const char *user = "", *salt = "", *opaque = NULL,
1733 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1735 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1736 !(cptr = strstr(desc, "authmod=llnw"))) {
1737 av_log(s, AV_LOG_ERROR,
1738 "Unknown connect error (unsupported authentication method?)\n");
1739 return AVERROR_UNKNOWN;
1741 cptr += strlen("authmod=");
1742 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1743 authmod[i++] = *cptr++;
1746 if (!rt->username[0] || !rt->password[0]) {
1747 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1748 return AVERROR_UNKNOWN;
1751 if (strstr(desc, "?reason=authfailed")) {
1752 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1753 return AVERROR_UNKNOWN;
1754 } else if (strstr(desc, "?reason=nosuchuser")) {
1755 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1756 return AVERROR_UNKNOWN;
1759 if (rt->auth_tried) {
1760 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1761 return AVERROR_UNKNOWN;
1764 rt->auth_params[0] = '\0';
1766 if (strstr(desc, "code=403 need auth")) {
1767 snprintf(rt->auth_params, sizeof(rt->auth_params),
1768 "?authmod=%s&user=%s", authmod, rt->username);
1772 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1773 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1774 return AVERROR_UNKNOWN;
1777 av_strlcpy(buf, cptr + 1, sizeof(buf));
1781 char *next = strchr(ptr, '&');
1782 char *value = strchr(ptr, '=');
1787 if (!strcmp(ptr, "user")) {
1789 } else if (!strcmp(ptr, "salt")) {
1791 } else if (!strcmp(ptr, "opaque")) {
1793 } else if (!strcmp(ptr, "challenge")) {
1795 } else if (!strcmp(ptr, "nonce")) {
1798 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1801 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1806 if (!strcmp(authmod, "adobe")) {
1807 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1810 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1818 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1820 RTMPContext *rt = s->priv_data;
1821 const uint8_t *data_end = pkt->data + pkt->size;
1822 char *tracked_method = NULL;
1823 int level = AV_LOG_ERROR;
1824 uint8_t tmpstr[256];
1827 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1830 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1831 "description", tmpstr, sizeof(tmpstr))) {
1832 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1833 !strcmp(tracked_method, "releaseStream") ||
1834 !strcmp(tracked_method, "FCSubscribe") ||
1835 !strcmp(tracked_method, "FCPublish"))) {
1836 /* Gracefully ignore Adobe-specific historical artifact errors. */
1837 level = AV_LOG_WARNING;
1839 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1840 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1842 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1843 ret = handle_connect_error(s, tmpstr);
1845 rt->do_reconnect = 1;
1846 level = AV_LOG_VERBOSE;
1849 ret = AVERROR_UNKNOWN;
1850 av_log(s, level, "Server error: %s\n", tmpstr);
1853 av_free(tracked_method);
1857 static int write_begin(URLContext *s)
1859 RTMPContext *rt = s->priv_data;
1861 RTMPPacket spkt = { 0 };
1864 // Send Stream Begin 1
1865 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1866 RTMP_PT_PING, 0, 6)) < 0) {
1867 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1871 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1872 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1873 bytestream2_put_be32(&pbc, rt->nb_streamid);
1875 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1876 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1878 ff_rtmp_packet_destroy(&spkt);
1883 static int write_status(URLContext *s, RTMPPacket *pkt,
1884 const char *status, const char *filename)
1886 RTMPContext *rt = s->priv_data;
1887 RTMPPacket spkt = { 0 };
1888 char statusmsg[128];
1892 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1894 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1895 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1900 spkt.extra = pkt->extra;
1901 ff_amf_write_string(&pp, "onStatus");
1902 ff_amf_write_number(&pp, 0);
1903 ff_amf_write_null(&pp);
1905 ff_amf_write_object_start(&pp);
1906 ff_amf_write_field_name(&pp, "level");
1907 ff_amf_write_string(&pp, "status");
1908 ff_amf_write_field_name(&pp, "code");
1909 ff_amf_write_string(&pp, status);
1910 ff_amf_write_field_name(&pp, "description");
1911 snprintf(statusmsg, sizeof(statusmsg),
1912 "%s is now published", filename);
1913 ff_amf_write_string(&pp, statusmsg);
1914 ff_amf_write_field_name(&pp, "details");
1915 ff_amf_write_string(&pp, filename);
1916 ff_amf_write_object_end(&pp);
1918 spkt.size = pp - spkt.data;
1919 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1920 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1921 ff_rtmp_packet_destroy(&spkt);
1926 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1928 RTMPContext *rt = s->priv_data;
1934 const uint8_t *p = pkt->data;
1936 RTMPPacket spkt = { 0 };
1940 bytestream2_init(&gbc, p, pkt->size);
1941 if (ff_amf_read_string(&gbc, command, sizeof(command),
1943 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1944 return AVERROR_INVALIDDATA;
1947 ret = ff_amf_read_number(&gbc, &seqnum);
1950 ret = ff_amf_read_null(&gbc);
1953 if (!strcmp(command, "FCPublish") ||
1954 !strcmp(command, "publish")) {
1955 ret = ff_amf_read_string(&gbc, filename,
1956 sizeof(filename), &stringlen);
1958 if (ret == AVERROR(EINVAL))
1959 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1961 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1966 pchar = strrchr(s->filename, '/');
1968 av_log(s, AV_LOG_WARNING,
1969 "Unable to find / in url %s, bad format\n",
1971 pchar = s->filename;
1974 if (strcmp(pchar, filename))
1975 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1976 " %s\n", filename, pchar);
1978 rt->state = STATE_RECEIVING;
1981 if (!strcmp(command, "FCPublish")) {
1982 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1984 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1985 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1989 ff_amf_write_string(&pp, "onFCPublish");
1990 } else if (!strcmp(command, "publish")) {
1991 ret = write_begin(s);
1995 // Send onStatus(NetStream.Publish.Start)
1996 return write_status(s, pkt, "NetStream.Publish.Start",
1998 } else if (!strcmp(command, "play")) {
1999 ret = write_begin(s);
2002 rt->state = STATE_SENDING;
2003 return write_status(s, pkt, "NetStream.Play.Start",
2006 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
2008 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
2009 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2013 ff_amf_write_string(&pp, "_result");
2014 ff_amf_write_number(&pp, seqnum);
2015 ff_amf_write_null(&pp);
2016 if (!strcmp(command, "createStream")) {
2018 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2019 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2020 ff_amf_write_number(&pp, rt->nb_streamid);
2021 /* By now we don't control which streams are removed in
2022 * deleteStream. There is no stream creation control
2023 * if a client creates more than 2^32 - 2 streams. */
2026 spkt.size = pp - spkt.data;
2027 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2028 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2029 ff_rtmp_packet_destroy(&spkt);
2034 * Read the AMF_NUMBER response ("_result") to a function call
2035 * (e.g. createStream()). This response should be made up of the AMF_STRING
2036 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2037 * successful response, we will return set the value to number (otherwise number
2038 * will not be changed).
2040 * @return 0 if reading the value succeeds, negative value otherwise
2042 static int read_number_result(RTMPPacket *pkt, double *number)
2044 // We only need to fit "_result" in this.
2045 uint8_t strbuffer[8];
2050 bytestream2_init(&gbc, pkt->data, pkt->size);
2052 // Value 1/4: "_result" as AMF_STRING
2053 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2054 return AVERROR_INVALIDDATA;
2055 if (strcmp(strbuffer, "_result"))
2056 return AVERROR_INVALIDDATA;
2057 // Value 2/4: The callee reference number
2058 if (ff_amf_read_number(&gbc, &numbuffer))
2059 return AVERROR_INVALIDDATA;
2061 if (ff_amf_read_null(&gbc))
2062 return AVERROR_INVALIDDATA;
2063 // Value 4/4: The response as AMF_NUMBER
2064 if (ff_amf_read_number(&gbc, &numbuffer))
2065 return AVERROR_INVALIDDATA;
2067 *number = numbuffer;
2072 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2074 RTMPContext *rt = s->priv_data;
2075 char *tracked_method = NULL;
2078 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2081 if (!tracked_method) {
2082 /* Ignore this reply when the current method is not tracked. */
2086 if (!strcmp(tracked_method, "connect")) {
2087 if (!rt->is_input) {
2088 if ((ret = gen_release_stream(s, rt)) < 0)
2091 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2094 if ((ret = gen_server_bw(s, rt)) < 0)
2098 if ((ret = gen_create_stream(s, rt)) < 0)
2102 /* Send the FCSubscribe command when the name of live
2103 * stream is defined by the user or if it's a live stream. */
2104 if (rt->subscribe) {
2105 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2107 } else if (rt->live == -1) {
2108 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2112 } else if (!strcmp(tracked_method, "createStream")) {
2114 if (read_number_result(pkt, &stream_id)) {
2115 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2117 rt->stream_id = stream_id;
2120 if (!rt->is_input) {
2121 if ((ret = gen_publish(s, rt)) < 0)
2124 if (rt->live != -1) {
2125 if ((ret = gen_get_stream_length(s, rt)) < 0)
2128 if ((ret = gen_play(s, rt)) < 0)
2130 if ((ret = gen_buffer_time(s, rt)) < 0)
2133 } else if (!strcmp(tracked_method, "getStreamLength")) {
2134 if (read_number_result(pkt, &rt->duration)) {
2135 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2140 av_free(tracked_method);
2144 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2146 RTMPContext *rt = s->priv_data;
2147 const uint8_t *data_end = pkt->data + pkt->size;
2148 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2149 uint8_t tmpstr[256];
2152 for (i = 0; i < 2; i++) {
2153 t = ff_amf_tag_size(ptr, data_end);
2159 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2160 if (!t && !strcmp(tmpstr, "error")) {
2161 t = ff_amf_get_field_value(ptr, data_end,
2162 "description", tmpstr, sizeof(tmpstr));
2163 if (t || !tmpstr[0])
2164 t = ff_amf_get_field_value(ptr, data_end, "code",
2165 tmpstr, sizeof(tmpstr));
2167 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2171 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2172 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2173 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2174 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2175 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2176 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2181 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2183 RTMPContext *rt = s->priv_data;
2186 //TODO: check for the messages sent for wrong state?
2187 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2188 if ((ret = handle_invoke_error(s, pkt)) < 0)
2190 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2191 if ((ret = handle_invoke_result(s, pkt)) < 0)
2193 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2194 if ((ret = handle_invoke_status(s, pkt)) < 0)
2196 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2197 if ((ret = gen_check_bw(s, rt)) < 0)
2199 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2200 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2201 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2202 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2203 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2204 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2205 if ((ret = send_invoke_response(s, pkt)) < 0)
2212 static int update_offset(RTMPContext *rt, int size)
2216 // generate packet header and put data into buffer for FLV demuxer
2217 if (rt->flv_off < rt->flv_size) {
2218 // There is old unread data in the buffer, thus append at the end
2219 old_flv_size = rt->flv_size;
2220 rt->flv_size += size;
2222 // All data has been read, write the new data at the start of the buffer
2224 rt->flv_size = size;
2228 return old_flv_size;
2231 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2233 int old_flv_size, ret;
2235 const uint8_t *data = pkt->data + skip;
2236 const int size = pkt->size - skip;
2237 uint32_t ts = pkt->timestamp;
2239 if (pkt->type == RTMP_PT_AUDIO) {
2241 } else if (pkt->type == RTMP_PT_VIDEO) {
2245 old_flv_size = update_offset(rt, size + 15);
2247 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2248 rt->flv_size = rt->flv_off = 0;
2251 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2252 bytestream2_skip_p(&pbc, old_flv_size);
2253 bytestream2_put_byte(&pbc, pkt->type);
2254 bytestream2_put_be24(&pbc, size);
2255 bytestream2_put_be24(&pbc, ts);
2256 bytestream2_put_byte(&pbc, ts >> 24);
2257 bytestream2_put_be24(&pbc, 0);
2258 bytestream2_put_buffer(&pbc, data, size);
2259 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2264 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2266 RTMPContext *rt = s->priv_data;
2267 uint8_t commandbuffer[64];
2268 char statusmsg[128];
2269 int stringlen, ret, skip = 0;
2272 bytestream2_init(&gbc, pkt->data, pkt->size);
2273 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2275 return AVERROR_INVALIDDATA;
2277 if (!strcmp(commandbuffer, "onMetaData")) {
2278 // metadata properties should be stored in a mixed array
2279 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2280 // We have found a metaData Array so flv can determine the streams
2282 rt->received_metadata = 1;
2283 // skip 32-bit max array index
2284 bytestream2_skip(&gbc, 4);
2285 while (bytestream2_get_bytes_left(&gbc) > 3) {
2286 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2288 return AVERROR_INVALIDDATA;
2289 // We do not care about the content of the property (yet).
2290 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2292 return AVERROR_INVALIDDATA;
2293 bytestream2_skip(&gbc, stringlen);
2295 // The presence of the following properties indicates that the
2296 // respective streams are present.
2297 if (!strcmp(statusmsg, "videocodecid")) {
2300 if (!strcmp(statusmsg, "audiocodecid")) {
2304 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2305 return AVERROR_INVALIDDATA;
2309 // Skip the @setDataFrame string and validate it is a notification
2310 if (!strcmp(commandbuffer, "@setDataFrame")) {
2311 skip = gbc.buffer - pkt->data;
2312 ret = ff_amf_read_string(&gbc, statusmsg,
2313 sizeof(statusmsg), &stringlen);
2315 return AVERROR_INVALIDDATA;
2318 return append_flv_data(rt, pkt, skip);
2322 * Parse received packet and possibly perform some action depending on
2323 * the packet contents.
2324 * @return 0 for no errors, negative values for serious errors which prevent
2325 * further communications, positive values for uncritical errors
2327 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2332 ff_rtmp_packet_dump(s, pkt);
2335 switch (pkt->type) {
2336 case RTMP_PT_BYTES_READ:
2337 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2339 case RTMP_PT_CHUNK_SIZE:
2340 if ((ret = handle_chunk_size(s, pkt)) < 0)
2344 if ((ret = handle_ping(s, pkt)) < 0)
2347 case RTMP_PT_CLIENT_BW:
2348 if ((ret = handle_client_bw(s, pkt)) < 0)
2351 case RTMP_PT_SERVER_BW:
2352 if ((ret = handle_server_bw(s, pkt)) < 0)
2355 case RTMP_PT_INVOKE:
2356 if ((ret = handle_invoke(s, pkt)) < 0)
2361 case RTMP_PT_METADATA:
2362 case RTMP_PT_NOTIFY:
2363 /* Audio, Video and Metadata packets are parsed in get_packet() */
2366 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2372 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2374 int ret, old_flv_size, type;
2375 const uint8_t *next;
2378 uint32_t ts, cts, pts = 0;
2380 old_flv_size = update_offset(rt, pkt->size);
2382 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2383 rt->flv_size = rt->flv_off = 0;
2388 p = rt->flv_data + old_flv_size;
2390 /* copy data while rewriting timestamps */
2391 ts = pkt->timestamp;
2393 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2394 type = bytestream_get_byte(&next);
2395 size = bytestream_get_be24(&next);
2396 cts = bytestream_get_be24(&next);
2397 cts |= bytestream_get_byte(&next) << 24;
2402 if (size + 3 + 4 > pkt->data + pkt->size - next)
2404 bytestream_put_byte(&p, type);
2405 bytestream_put_be24(&p, size);
2406 bytestream_put_be24(&p, ts);
2407 bytestream_put_byte(&p, ts >> 24);
2408 memcpy(p, next, size + 3 + 4);
2410 bytestream_put_be32(&p, size + RTMP_HEADER);
2411 next += size + 3 + 4;
2413 if (p != rt->flv_data + rt->flv_size) {
2414 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2415 "RTMP_PT_METADATA packet\n");
2416 rt->flv_size = p - rt->flv_data;
2423 * Interact with the server by receiving and sending RTMP packets until
2424 * there is some significant data (media data or expected status notification).
2426 * @param s reading context
2427 * @param for_header non-zero value tells function to work until it
2428 * gets notification from the server that playing has been started,
2429 * otherwise function will work until some media data is received (or
2431 * @return 0 for successful operation, negative value in case of error
2433 static int get_packet(URLContext *s, int for_header)
2435 RTMPContext *rt = s->priv_data;
2438 if (rt->state == STATE_STOPPED)
2442 RTMPPacket rpkt = { 0 };
2443 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2444 rt->in_chunk_size, &rt->prev_pkt[0],
2445 &rt->nb_prev_pkt[0])) <= 0) {
2447 return AVERROR(EAGAIN);
2449 return AVERROR(EIO);
2453 // Track timestamp for later use
2454 rt->last_timestamp = rpkt.timestamp;
2456 rt->bytes_read += ret;
2457 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2458 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2459 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2461 rt->last_bytes_read = rt->bytes_read;
2464 ret = rtmp_parse_result(s, rt, &rpkt);
2466 // At this point we must check if we are in the seek state and continue
2467 // with the next packet. handle_invoke will get us out of this state
2468 // when the right message is encountered
2469 if (rt->state == STATE_SEEKING) {
2470 ff_rtmp_packet_destroy(&rpkt);
2471 // We continue, let the natural flow of things happen:
2472 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2476 if (ret < 0) {//serious error in current packet
2477 ff_rtmp_packet_destroy(&rpkt);
2480 if (rt->do_reconnect && for_header) {
2481 ff_rtmp_packet_destroy(&rpkt);
2484 if (rt->state == STATE_STOPPED) {
2485 ff_rtmp_packet_destroy(&rpkt);
2488 if (for_header && (rt->state == STATE_PLAYING ||
2489 rt->state == STATE_PUBLISHING ||
2490 rt->state == STATE_SENDING ||
2491 rt->state == STATE_RECEIVING)) {
2492 ff_rtmp_packet_destroy(&rpkt);
2495 if (!rpkt.size || !rt->is_input) {
2496 ff_rtmp_packet_destroy(&rpkt);
2499 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2500 ret = append_flv_data(rt, &rpkt, 0);
2501 ff_rtmp_packet_destroy(&rpkt);
2503 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2504 ret = handle_notify(s, &rpkt);
2505 ff_rtmp_packet_destroy(&rpkt);
2507 } else if (rpkt.type == RTMP_PT_METADATA) {
2508 ret = handle_metadata(rt, &rpkt);
2509 ff_rtmp_packet_destroy(&rpkt);
2512 ff_rtmp_packet_destroy(&rpkt);
2516 static int rtmp_close(URLContext *h)
2518 RTMPContext *rt = h->priv_data;
2521 if (!rt->is_input) {
2522 rt->flv_data = NULL;
2523 if (rt->out_pkt.size)
2524 ff_rtmp_packet_destroy(&rt->out_pkt);
2525 if (rt->state > STATE_FCPUBLISH)
2526 ret = gen_fcunpublish_stream(h, rt);
2528 if (rt->state > STATE_HANDSHAKED)
2529 ret = gen_delete_stream(h, rt);
2530 for (i = 0; i < 2; i++) {
2531 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2532 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2533 av_freep(&rt->prev_pkt[i]);
2536 free_tracked_methods(rt);
2537 av_freep(&rt->flv_data);
2538 ffurl_close(rt->stream);
2543 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2544 * demuxer about the duration of the stream.
2546 * This should only be done if there was no real onMetadata packet sent by the
2547 * server at the start of the stream and if we were able to retrieve a valid
2548 * duration via a getStreamLength call.
2550 * @return 0 for successful operation, negative value in case of error
2552 static int inject_fake_duration_metadata(RTMPContext *rt)
2554 // We need to insert the metadata packet directly after the FLV
2555 // header, i.e. we need to move all other already read data by the
2556 // size of our fake metadata packet.
2559 // Keep old flv_data pointer
2560 uint8_t* old_flv_data = rt->flv_data;
2561 // Allocate a new flv_data pointer with enough space for the additional package
2562 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2563 rt->flv_data = old_flv_data;
2564 return AVERROR(ENOMEM);
2568 memcpy(rt->flv_data, old_flv_data, 13);
2569 // Copy remaining packets
2570 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2571 // Increase the size by the injected packet
2573 // Delete the old FLV data
2574 av_freep(&old_flv_data);
2576 p = rt->flv_data + 13;
2577 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2578 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2579 bytestream_put_be24(&p, 0); // timestamp
2580 bytestream_put_be32(&p, 0); // reserved
2582 // first event name as a string
2583 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2584 // "onMetaData" as AMF string
2585 bytestream_put_be16(&p, 10);
2586 bytestream_put_buffer(&p, "onMetaData", 10);
2588 // mixed array (hash) with size and string/type/data tuples
2589 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2590 bytestream_put_be32(&p, 1); // metadata_count
2592 // "duration" as AMF string
2593 bytestream_put_be16(&p, 8);
2594 bytestream_put_buffer(&p, "duration", 8);
2595 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2596 bytestream_put_be64(&p, av_double2int(rt->duration));
2599 bytestream_put_be16(&p, 0); // Empty string
2600 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2601 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2607 * Open RTMP connection and verify that the stream can be played.
2609 * URL syntax: rtmp://server[:port][/app][/playpath]
2610 * where 'app' is first one or two directories in the path
2611 * (e.g. /ondemand/, /flash/live/, etc.)
2612 * and 'playpath' is a file name (the rest of the path,
2613 * may be prefixed with "mp4:")
2615 static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2617 RTMPContext *rt = s->priv_data;
2618 char proto[8], hostname[256], path[1024], auth[100], *fname;
2619 char *old_app, *qmark, *n, fname_buffer[1024];
2624 if (rt->listen_timeout > 0)
2627 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2629 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2630 hostname, sizeof(hostname), &port,
2631 path, sizeof(path), s->filename);
2633 n = strchr(path, ' ');
2635 av_log(s, AV_LOG_WARNING,
2636 "Detected librtmp style URL parameters, these aren't supported "
2637 "by the libavformat internal RTMP handler currently enabled. "
2638 "See the documentation for the correct way to pass parameters.\n");
2639 *n = '\0'; // Trim not supported part
2643 char *ptr = strchr(auth, ':');
2646 av_strlcpy(rt->username, auth, sizeof(rt->username));
2647 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2651 if (rt->listen && strcmp(proto, "rtmp")) {
2652 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2654 return AVERROR(EINVAL);
2656 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2657 if (!strcmp(proto, "rtmpts"))
2658 av_dict_set(opts, "ffrtmphttp_tls", "1", 1);
2660 /* open the http tunneling connection */
2661 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2662 } else if (!strcmp(proto, "rtmps")) {
2663 /* open the tls connection */
2665 port = RTMPS_DEFAULT_PORT;
2666 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2667 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2668 if (!strcmp(proto, "rtmpte"))
2669 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2671 /* open the encrypted connection */
2672 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2675 /* open the tcp connection */
2677 port = RTMP_DEFAULT_PORT;
2679 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2680 "?listen&listen_timeout=%d",
2681 rt->listen_timeout * 1000);
2683 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2687 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2688 &s->interrupt_callback, opts,
2689 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2690 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2694 if (rt->swfverify) {
2695 if ((ret = rtmp_calc_swfhash(s)) < 0)
2699 rt->state = STATE_START;
2700 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2702 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2705 rt->out_chunk_size = 128;
2706 rt->in_chunk_size = 128; // Probably overwritten later
2707 rt->state = STATE_HANDSHAKED;
2709 // Keep the application name when it has been defined by the user.
2712 rt->app = av_malloc(APP_MAX_LENGTH);
2714 ret = AVERROR(ENOMEM);
2718 //extract "app" part from path
2719 qmark = strchr(path, '?');
2720 if (qmark && strstr(qmark, "slist=")) {
2722 // After slist we have the playpath, the full path is used as app
2723 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2724 fname = strstr(path, "slist=") + 6;
2725 // Strip any further query parameters from fname
2726 amp = strchr(fname, '&');
2728 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2729 sizeof(fname_buffer)));
2730 fname = fname_buffer;
2732 } else if (!strncmp(path, "/ondemand/", 10)) {
2734 memcpy(rt->app, "ondemand", 9);
2736 char *next = *path ? path + 1 : path;
2737 char *p = strchr(next, '/');
2740 // If name of application has been defined by the user, assume that
2741 // playpath is provided in the URL
2745 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2748 // make sure we do not mismatch a playpath for an application instance
2749 char *c = strchr(p + 1, ':');
2750 fname = strchr(p + 1, '/');
2751 if (!fname || (c && c < fname)) {
2753 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2756 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2762 // The name of application has been defined by the user, override it.
2763 if (strlen(old_app) >= APP_MAX_LENGTH) {
2764 ret = AVERROR(EINVAL);
2771 if (!rt->playpath) {
2772 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2773 if (!rt->playpath) {
2774 ret = AVERROR(ENOMEM);
2779 int len = strlen(fname);
2780 if (!strchr(fname, ':') && len >= 4 &&
2781 (!strcmp(fname + len - 4, ".f4v") ||
2782 !strcmp(fname + len - 4, ".mp4"))) {
2783 memcpy(rt->playpath, "mp4:", 5);
2785 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2786 fname[len - 4] = '\0';
2787 rt->playpath[0] = 0;
2789 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2791 rt->playpath[0] = '\0';
2796 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2798 ret = AVERROR(ENOMEM);
2801 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2802 port, "/%s", rt->app);
2805 if (!rt->flashver) {
2806 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2807 if (!rt->flashver) {
2808 ret = AVERROR(ENOMEM);
2812 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2813 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2814 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2816 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2817 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2821 rt->client_report_size = 1048576;
2825 rt->received_metadata = 0;
2826 rt->last_bytes_read = 0;
2827 rt->server_bw = 2500000;
2830 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2831 proto, path, rt->app, rt->playpath);
2833 if ((ret = gen_connect(s, rt)) < 0)
2836 if ((ret = read_connect(s, s->priv_data)) < 0)
2841 ret = get_packet(s, 1);
2842 } while (ret == AVERROR(EAGAIN));
2846 if (rt->do_reconnect) {
2848 ffurl_close(rt->stream);
2850 rt->do_reconnect = 0;
2852 for (i = 0; i < 2; i++)
2853 memset(rt->prev_pkt[i], 0,
2854 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2855 free_tracked_methods(rt);
2860 // generate FLV header for demuxer
2862 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2865 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2867 // Read packets until we reach the first A/V packet or read metadata.
2868 // If there was a metadata package in front of the A/V packets, we can
2869 // build the FLV header from this. If we do not receive any metadata,
2870 // the FLV decoder will allocate the needed streams when their first
2871 // audio or video packet arrives.
2872 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2873 if ((ret = get_packet(s, 0)) < 0)
2877 // Either after we have read the metadata or (if there is none) the
2878 // first packet of an A/V stream, we have a better knowledge about the
2879 // streams, so set the FLV header accordingly.
2880 if (rt->has_audio) {
2881 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2883 if (rt->has_video) {
2884 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2887 // If we received the first packet of an A/V stream and no metadata but
2888 // the server returned a valid duration, create a fake metadata packet
2889 // to inform the FLV decoder about the duration.
2890 if (!rt->received_metadata && rt->duration > 0) {
2891 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2896 rt->flv_data = NULL;
2898 rt->skip_bytes = 13;
2901 s->max_packet_size = rt->stream->max_packet_size;
2911 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2913 RTMPContext *rt = s->priv_data;
2914 int orig_size = size;
2918 int data_left = rt->flv_size - rt->flv_off;
2920 if (data_left >= size) {
2921 memcpy(buf, rt->flv_data + rt->flv_off, size);
2922 rt->flv_off += size;
2925 if (data_left > 0) {
2926 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2929 rt->flv_off = rt->flv_size;
2932 if ((ret = get_packet(s, 0)) < 0)
2938 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2941 RTMPContext *rt = s->priv_data;
2943 av_log(s, AV_LOG_DEBUG,
2944 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2945 stream_index, timestamp, flags);
2946 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2947 av_log(s, AV_LOG_ERROR,
2948 "Unable to send seek command on stream index %d at timestamp "
2949 "%"PRId64" with flags %08x\n",
2950 stream_index, timestamp, flags);
2953 rt->flv_off = rt->flv_size;
2954 rt->state = STATE_SEEKING;
2958 static int rtmp_pause(URLContext *s, int pause)
2960 RTMPContext *rt = s->priv_data;
2962 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2963 rt->last_timestamp);
2964 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2965 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2966 rt->last_timestamp);
2972 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2974 RTMPContext *rt = s->priv_data;
2975 int size_temp = size;
2976 int pktsize, pkttype, copy;
2978 const uint8_t *buf_temp = buf;
2983 if (rt->skip_bytes) {
2984 int skip = FFMIN(rt->skip_bytes, size_temp);
2987 rt->skip_bytes -= skip;
2991 if (rt->flv_header_bytes < RTMP_HEADER) {
2992 const uint8_t *header = rt->flv_header;
2993 int channel = RTMP_AUDIO_CHANNEL;
2995 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2996 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2997 rt->flv_header_bytes += copy;
2999 if (rt->flv_header_bytes < RTMP_HEADER)
3002 pkttype = bytestream_get_byte(&header);
3003 pktsize = bytestream_get_be24(&header);
3004 ts = bytestream_get_be24(&header);
3005 ts |= bytestream_get_byte(&header) << 24;
3006 bytestream_get_be24(&header);
3007 rt->flv_size = pktsize;
3009 if (pkttype == RTMP_PT_VIDEO)
3010 channel = RTMP_VIDEO_CHANNEL;
3012 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
3013 pkttype == RTMP_PT_NOTIFY) {
3014 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
3015 &rt->nb_prev_pkt[1],
3018 // Force sending a full 12 bytes header by clearing the
3019 // channel id, to make it not match a potential earlier
3020 // packet in the same channel.
3021 rt->prev_pkt[1][channel].channel_id = 0;
3024 //this can be a big packet, it's better to send it right here
3025 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3026 pkttype, ts, pktsize)) < 0)
3029 rt->out_pkt.extra = rt->stream_id;
3030 rt->flv_data = rt->out_pkt.data;
3033 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3034 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3035 rt->flv_off += copy;
3038 if (rt->flv_off == rt->flv_size) {
3041 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3042 // For onMetaData and |RtmpSampleAccess packets, we want
3043 // @setDataFrame prepended to the packet before it gets sent.
3044 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3046 uint8_t commandbuffer[64];
3050 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3051 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3053 if (!strcmp(commandbuffer, "onMetaData") ||
3054 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3056 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3057 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3060 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3061 rt->out_pkt.size += 16;
3062 ptr = rt->out_pkt.data;
3063 ff_amf_write_string(&ptr, "@setDataFrame");
3068 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3072 rt->flv_header_bytes = 0;
3073 rt->flv_nb_packets++;
3075 } while (buf_temp - buf < size);
3077 if (rt->flv_nb_packets < rt->flush_interval)
3079 rt->flv_nb_packets = 0;
3081 /* set stream into nonblocking mode */
3082 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3084 /* try to read one byte from the stream */
3085 ret = ffurl_read(rt->stream, &c, 1);
3087 /* switch the stream back into blocking mode */
3088 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3090 if (ret == AVERROR(EAGAIN)) {
3091 /* no incoming data to handle */
3093 } else if (ret < 0) {
3095 } else if (ret == 1) {
3096 RTMPPacket rpkt = { 0 };
3098 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3101 &rt->nb_prev_pkt[0], c)) <= 0)
3104 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3107 ff_rtmp_packet_destroy(&rpkt);
3113 #define OFFSET(x) offsetof(RTMPContext, x)
3114 #define DEC AV_OPT_FLAG_DECODING_PARAM
3115 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3117 static const AVOption rtmp_options[] = {
3118 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3119 {"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},
3120 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3121 {"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},
3122 {"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},
3123 {"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"},
3124 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3125 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3126 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3127 {"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},
3128 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3129 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3130 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3131 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3132 {"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},
3133 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3134 {"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},
3135 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3136 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3137 {"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" },
3141 #define RTMP_PROTOCOL(flavor) \
3142 static const AVClass flavor##_class = { \
3143 .class_name = #flavor, \
3144 .item_name = av_default_item_name, \
3145 .option = rtmp_options, \
3146 .version = LIBAVUTIL_VERSION_INT, \
3149 const URLProtocol ff_##flavor##_protocol = { \
3151 .url_open2 = rtmp_open, \
3152 .url_read = rtmp_read, \
3153 .url_read_seek = rtmp_seek, \
3154 .url_read_pause = rtmp_pause, \
3155 .url_write = rtmp_write, \
3156 .url_close = rtmp_close, \
3157 .priv_data_size = sizeof(RTMPContext), \
3158 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3159 .priv_data_class= &flavor##_class, \
3164 RTMP_PROTOCOL(rtmpe)
3165 RTMP_PROTOCOL(rtmps)
3166 RTMP_PROTOCOL(rtmpt)
3167 RTMP_PROTOCOL(rtmpte)
3168 RTMP_PROTOCOL(rtmpts)