2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/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 128
52 #define PLAYPATH_MAX_LENGTH 256
53 #define TCURL_MAX_LENGTH 512
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 uint32_t bytes_read; ///< number of bytes read from server
98 uint32_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);
160 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
164 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
165 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
166 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
167 sizeof(*rt->tracked_methods))) < 0) {
168 rt->nb_tracked_methods = 0;
169 rt->tracked_methods_size = 0;
174 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
175 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
176 return AVERROR(ENOMEM);
177 rt->tracked_methods[rt->nb_tracked_methods].id = id;
178 rt->nb_tracked_methods++;
183 static void del_tracked_method(RTMPContext *rt, int index)
185 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
186 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
187 rt->nb_tracked_methods--;
190 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
191 char **tracked_method)
193 RTMPContext *rt = s->priv_data;
199 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
200 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
203 for (i = 0; i < rt->nb_tracked_methods; i++) {
204 if (rt->tracked_methods[i].id != pkt_id)
207 *tracked_method = rt->tracked_methods[i].name;
208 del_tracked_method(rt, i);
215 static void free_tracked_methods(RTMPContext *rt)
219 for (i = 0; i < rt->nb_tracked_methods; i ++)
220 av_free(rt->tracked_methods[i].name);
221 av_free(rt->tracked_methods);
222 rt->tracked_methods = NULL;
223 rt->tracked_methods_size = 0;
224 rt->nb_tracked_methods = 0;
227 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
231 if (pkt->type == RTMP_PT_INVOKE && track) {
237 bytestream2_init(&gbc, pkt->data, pkt->size);
238 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
241 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
244 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
248 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
249 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
251 ff_rtmp_packet_destroy(pkt);
255 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
260 /* The type must be B for Boolean, N for number, S for string, O for
261 * object, or Z for null. For Booleans the data must be either 0 or 1 for
262 * FALSE or TRUE, respectively. Likewise for Objects the data must be
263 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
264 * may be named, by prefixing the type with 'N' and specifying the name
265 * before the value (ie. NB:myFlag:1). This option may be used multiple times
266 * to construct arbitrary AMF sequences. */
267 if (param[0] && param[1] == ':') {
270 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
273 value = strchr(field, ':');
279 ff_amf_write_field_name(p, field);
286 ff_amf_write_bool(p, value[0] != '0');
289 ff_amf_write_string(p, value);
292 ff_amf_write_number(p, strtod(value, NULL));
295 ff_amf_write_null(p);
299 ff_amf_write_object_start(p);
301 ff_amf_write_object_end(p);
311 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
312 return AVERROR(EINVAL);
316 * Generate 'connect' call and send it to the server.
318 static int gen_connect(URLContext *s, RTMPContext *rt)
324 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
330 ff_amf_write_string(&p, "connect");
331 ff_amf_write_number(&p, ++rt->nb_invokes);
332 ff_amf_write_object_start(&p);
333 ff_amf_write_field_name(&p, "app");
334 ff_amf_write_string2(&p, rt->app, rt->auth_params);
337 ff_amf_write_field_name(&p, "type");
338 ff_amf_write_string(&p, "nonprivate");
340 ff_amf_write_field_name(&p, "flashVer");
341 ff_amf_write_string(&p, rt->flashver);
344 ff_amf_write_field_name(&p, "swfUrl");
345 ff_amf_write_string(&p, rt->swfurl);
348 ff_amf_write_field_name(&p, "tcUrl");
349 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
351 ff_amf_write_field_name(&p, "fpad");
352 ff_amf_write_bool(&p, 0);
353 ff_amf_write_field_name(&p, "capabilities");
354 ff_amf_write_number(&p, 15.0);
356 /* Tell the server we support all the audio codecs except
357 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
358 * which are unused in the RTMP protocol implementation. */
359 ff_amf_write_field_name(&p, "audioCodecs");
360 ff_amf_write_number(&p, 4071.0);
361 ff_amf_write_field_name(&p, "videoCodecs");
362 ff_amf_write_number(&p, 252.0);
363 ff_amf_write_field_name(&p, "videoFunction");
364 ff_amf_write_number(&p, 1.0);
367 ff_amf_write_field_name(&p, "pageUrl");
368 ff_amf_write_string(&p, rt->pageurl);
371 ff_amf_write_object_end(&p);
374 char *param = rt->conn;
376 // Write arbitrary AMF data to the Connect message.
379 param += strspn(param, " ");
382 sep = strchr(param, ' ');
385 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
386 // Invalid AMF parameter.
387 ff_rtmp_packet_destroy(&pkt);
398 pkt.size = p - pkt.data;
400 return rtmp_send_packet(rt, &pkt, 1);
403 static int read_connect(URLContext *s, RTMPContext *rt)
405 RTMPPacket pkt = { 0 };
415 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
416 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
419 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
420 if ((ret = handle_chunk_size(s, &pkt)) < 0)
422 ff_rtmp_packet_destroy(&pkt);
423 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
424 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
429 bytestream2_init(&gbc, cp, pkt.size);
430 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
431 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
432 ff_rtmp_packet_destroy(&pkt);
433 return AVERROR_INVALIDDATA;
435 if (strcmp(command, "connect")) {
436 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
437 ff_rtmp_packet_destroy(&pkt);
438 return AVERROR_INVALIDDATA;
440 ret = ff_amf_read_number(&gbc, &seqnum);
442 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
443 /* Here one could parse an AMF Object with data as flashVers and others. */
444 ret = ff_amf_get_field_value(gbc.buffer,
445 gbc.buffer + bytestream2_get_bytes_left(&gbc),
446 "app", tmpstr, sizeof(tmpstr));
448 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
449 if (!ret && strcmp(tmpstr, rt->app))
450 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
452 ff_rtmp_packet_destroy(&pkt);
454 // Send Window Acknowledgement Size (as defined in specification)
455 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
456 RTMP_PT_SERVER_BW, 0, 4)) < 0)
459 bytestream_put_be32(&p, rt->server_bw);
460 pkt.size = p - pkt.data;
461 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
462 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
463 ff_rtmp_packet_destroy(&pkt);
466 // Send Peer Bandwidth
467 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
468 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
471 bytestream_put_be32(&p, rt->server_bw);
472 bytestream_put_byte(&p, 2); // dynamic
473 pkt.size = p - pkt.data;
474 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
475 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
476 ff_rtmp_packet_destroy(&pkt);
481 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
482 RTMP_PT_PING, 0, 6)) < 0)
486 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
487 bytestream_put_be32(&p, 0);
488 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
489 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
490 ff_rtmp_packet_destroy(&pkt);
495 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
496 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
500 bytestream_put_be32(&p, rt->out_chunk_size);
501 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
502 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
503 ff_rtmp_packet_destroy(&pkt);
507 // Send _result NetConnection.Connect.Success to connect
508 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
510 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
514 ff_amf_write_string(&p, "_result");
515 ff_amf_write_number(&p, seqnum);
517 ff_amf_write_object_start(&p);
518 ff_amf_write_field_name(&p, "fmsVer");
519 ff_amf_write_string(&p, "FMS/3,0,1,123");
520 ff_amf_write_field_name(&p, "capabilities");
521 ff_amf_write_number(&p, 31);
522 ff_amf_write_object_end(&p);
524 ff_amf_write_object_start(&p);
525 ff_amf_write_field_name(&p, "level");
526 ff_amf_write_string(&p, "status");
527 ff_amf_write_field_name(&p, "code");
528 ff_amf_write_string(&p, "NetConnection.Connect.Success");
529 ff_amf_write_field_name(&p, "description");
530 ff_amf_write_string(&p, "Connection succeeded.");
531 ff_amf_write_field_name(&p, "objectEncoding");
532 ff_amf_write_number(&p, 0);
533 ff_amf_write_object_end(&p);
535 pkt.size = p - pkt.data;
536 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
537 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
538 ff_rtmp_packet_destroy(&pkt);
542 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
543 RTMP_PT_INVOKE, 0, 30)) < 0)
546 ff_amf_write_string(&p, "onBWDone");
547 ff_amf_write_number(&p, 0);
548 ff_amf_write_null(&p);
549 ff_amf_write_number(&p, 8192);
550 pkt.size = p - pkt.data;
551 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
552 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
553 ff_rtmp_packet_destroy(&pkt);
559 * Generate 'releaseStream' call and send it to the server. It should make
560 * the server release some channel for media streams.
562 static int gen_release_stream(URLContext *s, RTMPContext *rt)
568 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
569 0, 29 + strlen(rt->playpath))) < 0)
572 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
574 ff_amf_write_string(&p, "releaseStream");
575 ff_amf_write_number(&p, ++rt->nb_invokes);
576 ff_amf_write_null(&p);
577 ff_amf_write_string(&p, rt->playpath);
579 return rtmp_send_packet(rt, &pkt, 1);
583 * Generate 'FCPublish' call and send it to the server. It should make
584 * the server prepare for receiving media streams.
586 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
592 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
593 0, 25 + strlen(rt->playpath))) < 0)
596 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
598 ff_amf_write_string(&p, "FCPublish");
599 ff_amf_write_number(&p, ++rt->nb_invokes);
600 ff_amf_write_null(&p);
601 ff_amf_write_string(&p, rt->playpath);
603 return rtmp_send_packet(rt, &pkt, 1);
607 * Generate 'FCUnpublish' call and send it to the server. It should make
608 * the server destroy stream.
610 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
616 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
617 0, 27 + strlen(rt->playpath))) < 0)
620 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
622 ff_amf_write_string(&p, "FCUnpublish");
623 ff_amf_write_number(&p, ++rt->nb_invokes);
624 ff_amf_write_null(&p);
625 ff_amf_write_string(&p, rt->playpath);
627 return rtmp_send_packet(rt, &pkt, 0);
631 * Generate 'createStream' call and send it to the server. It should make
632 * the server allocate some channel for media streams.
634 static int gen_create_stream(URLContext *s, RTMPContext *rt)
640 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
642 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
647 ff_amf_write_string(&p, "createStream");
648 ff_amf_write_number(&p, ++rt->nb_invokes);
649 ff_amf_write_null(&p);
651 return rtmp_send_packet(rt, &pkt, 1);
656 * Generate 'deleteStream' call and send it to the server. It should make
657 * the server remove some channel for media streams.
659 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
665 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
667 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
672 ff_amf_write_string(&p, "deleteStream");
673 ff_amf_write_number(&p, ++rt->nb_invokes);
674 ff_amf_write_null(&p);
675 ff_amf_write_number(&p, rt->stream_id);
677 return rtmp_send_packet(rt, &pkt, 0);
681 * Generate 'getStreamLength' call and send it to the server. If the server
682 * knows the duration of the selected stream, it will reply with the duration
685 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
691 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
692 0, 31 + strlen(rt->playpath))) < 0)
696 ff_amf_write_string(&p, "getStreamLength");
697 ff_amf_write_number(&p, ++rt->nb_invokes);
698 ff_amf_write_null(&p);
699 ff_amf_write_string(&p, rt->playpath);
701 return rtmp_send_packet(rt, &pkt, 1);
705 * Generate client buffer time and send it to the server.
707 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
713 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
718 bytestream_put_be16(&p, 3);
719 bytestream_put_be32(&p, rt->stream_id);
720 bytestream_put_be32(&p, rt->client_buffer_time);
722 return rtmp_send_packet(rt, &pkt, 0);
726 * Generate 'play' call and send it to the server, then ping the server
727 * to start actual playing.
729 static int gen_play(URLContext *s, RTMPContext *rt)
735 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
737 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
738 0, 29 + strlen(rt->playpath))) < 0)
741 pkt.extra = rt->stream_id;
744 ff_amf_write_string(&p, "play");
745 ff_amf_write_number(&p, ++rt->nb_invokes);
746 ff_amf_write_null(&p);
747 ff_amf_write_string(&p, rt->playpath);
748 ff_amf_write_number(&p, rt->live * 1000);
750 return rtmp_send_packet(rt, &pkt, 1);
753 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
759 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
762 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
765 pkt.extra = rt->stream_id;
768 ff_amf_write_string(&p, "seek");
769 ff_amf_write_number(&p, 0); //no tracking back responses
770 ff_amf_write_null(&p); //as usual, the first null param
771 ff_amf_write_number(&p, timestamp); //where we want to jump
773 return rtmp_send_packet(rt, &pkt, 1);
777 * Generate a pause packet that either pauses or unpauses the current stream.
779 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
785 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
788 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
791 pkt.extra = rt->stream_id;
794 ff_amf_write_string(&p, "pause");
795 ff_amf_write_number(&p, 0); //no tracking back responses
796 ff_amf_write_null(&p); //as usual, the first null param
797 ff_amf_write_bool(&p, pause); // pause or unpause
798 ff_amf_write_number(&p, timestamp); //where we pause the stream
800 return rtmp_send_packet(rt, &pkt, 1);
804 * Generate 'publish' call and send it to the server.
806 static int gen_publish(URLContext *s, RTMPContext *rt)
812 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
814 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
815 0, 30 + strlen(rt->playpath))) < 0)
818 pkt.extra = rt->stream_id;
821 ff_amf_write_string(&p, "publish");
822 ff_amf_write_number(&p, ++rt->nb_invokes);
823 ff_amf_write_null(&p);
824 ff_amf_write_string(&p, rt->playpath);
825 ff_amf_write_string(&p, "live");
827 return rtmp_send_packet(rt, &pkt, 1);
831 * Generate ping reply and send it to the server.
833 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
839 if (ppkt->size < 6) {
840 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
842 return AVERROR_INVALIDDATA;
845 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
846 ppkt->timestamp + 1, 6)) < 0)
850 bytestream_put_be16(&p, 7);
851 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
853 return rtmp_send_packet(rt, &pkt, 0);
857 * Generate SWF verification message and send it to the server.
859 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
865 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
866 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
871 bytestream_put_be16(&p, 27);
872 memcpy(p, rt->swfverification, 42);
874 return rtmp_send_packet(rt, &pkt, 0);
878 * Generate server bandwidth message and send it to the server.
880 static int gen_server_bw(URLContext *s, RTMPContext *rt)
886 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
891 bytestream_put_be32(&p, rt->server_bw);
893 return rtmp_send_packet(rt, &pkt, 0);
897 * Generate check bandwidth message and send it to the server.
899 static int gen_check_bw(URLContext *s, RTMPContext *rt)
905 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
910 ff_amf_write_string(&p, "_checkbw");
911 ff_amf_write_number(&p, ++rt->nb_invokes);
912 ff_amf_write_null(&p);
914 return rtmp_send_packet(rt, &pkt, 1);
918 * Generate report on bytes read so far and send it to the server.
920 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
926 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
931 bytestream_put_be32(&p, rt->bytes_read);
933 return rtmp_send_packet(rt, &pkt, 0);
936 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
937 const char *subscribe)
943 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
944 0, 27 + strlen(subscribe))) < 0)
948 ff_amf_write_string(&p, "FCSubscribe");
949 ff_amf_write_number(&p, ++rt->nb_invokes);
950 ff_amf_write_null(&p);
951 ff_amf_write_string(&p, subscribe);
953 return rtmp_send_packet(rt, &pkt, 1);
956 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
957 const uint8_t *key, int keylen, uint8_t *dst)
961 hmac = av_hmac_alloc(AV_HMAC_SHA256);
963 return AVERROR(ENOMEM);
965 av_hmac_init(hmac, key, keylen);
967 av_hmac_update(hmac, src, len);
968 } else { //skip 32 bytes used for storing digest
969 av_hmac_update(hmac, src, gap);
970 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
972 av_hmac_final(hmac, dst, 32);
979 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
982 int i, digest_pos = 0;
984 for (i = 0; i < 4; i++)
985 digest_pos += buf[i + off];
986 digest_pos = digest_pos % mod_val + add_val;
992 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
993 * will be stored) into that packet.
995 * @param buf handshake data (1536 bytes)
996 * @param encrypted use an encrypted connection (RTMPE)
997 * @return offset to the digest inside input data
999 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1001 int ret, digest_pos;
1004 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1006 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1008 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1009 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1018 * Verify that the received server response has the expected digest value.
1020 * @param buf handshake data received from the server (1536 bytes)
1021 * @param off position to search digest offset from
1022 * @return 0 if digest is valid, digest position otherwise
1024 static int rtmp_validate_digest(uint8_t *buf, int off)
1027 int ret, digest_pos;
1029 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1031 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1032 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1037 if (!memcmp(digest, buf + digest_pos, 32))
1042 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1048 if (rt->swfhash_len != 32) {
1049 av_log(s, AV_LOG_ERROR,
1050 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1051 return AVERROR(EINVAL);
1054 p = &rt->swfverification[0];
1055 bytestream_put_byte(&p, 1);
1056 bytestream_put_byte(&p, 1);
1057 bytestream_put_be32(&p, rt->swfsize);
1058 bytestream_put_be32(&p, rt->swfsize);
1060 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1067 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1068 uint8_t **out_data, int64_t *out_size)
1070 z_stream zs = { 0 };
1075 zs.avail_in = in_size;
1076 zs.next_in = in_data;
1077 ret = inflateInit(&zs);
1079 return AVERROR_UNKNOWN;
1082 uint8_t tmp_buf[16384];
1084 zs.avail_out = sizeof(tmp_buf);
1085 zs.next_out = tmp_buf;
1087 ret = inflate(&zs, Z_NO_FLUSH);
1088 if (ret != Z_OK && ret != Z_STREAM_END) {
1089 ret = AVERROR_UNKNOWN;
1093 size = sizeof(tmp_buf) - zs.avail_out;
1094 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1095 ret = AVERROR(ENOMEM);
1100 memcpy(*out_data + *out_size, tmp_buf, size);
1102 } while (zs.avail_out == 0);
1110 static int rtmp_calc_swfhash(URLContext *s)
1112 RTMPContext *rt = s->priv_data;
1113 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1114 int64_t in_size, out_size;
1120 /* Get the SWF player file. */
1121 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1122 &s->interrupt_callback, NULL, s->protocols, s)) < 0) {
1123 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1127 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1132 if (!(in_data = av_malloc(in_size))) {
1133 ret = AVERROR(ENOMEM);
1137 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1141 ret = AVERROR_INVALIDDATA;
1145 if (!memcmp(in_data, "CWS", 3)) {
1146 /* Decompress the SWF player file using Zlib. */
1147 if (!(out_data = av_malloc(8))) {
1148 ret = AVERROR(ENOMEM);
1151 *in_data = 'F'; // magic stuff
1152 memcpy(out_data, in_data, 8);
1156 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1157 &out_data, &out_size)) < 0)
1160 av_log(s, AV_LOG_ERROR,
1161 "Zlib is required for decompressing the SWF player file.\n");
1162 ret = AVERROR(EINVAL);
1172 /* Compute the SHA256 hash of the SWF player file. */
1173 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1174 "Genuine Adobe Flash Player 001", 30,
1178 /* Set SWFVerification parameters. */
1179 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1180 rt->swfsize = swfsize;
1184 av_freep(&out_data);
1185 ffurl_close(stream);
1190 * Perform handshake with the server by means of exchanging pseudorandom data
1191 * signed with HMAC-SHA2 digest.
1193 * @return 0 if handshake succeeds, negative value otherwise
1195 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1198 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1199 3, // unencrypted data
1200 0, 0, 0, 0, // client uptime
1206 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1207 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1209 int server_pos, client_pos;
1210 uint8_t digest[32], signature[32];
1213 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1215 av_lfg_init(&rnd, 0xDEADC0DE);
1216 // generate handshake packet - 1536 bytes of pseudorandom data
1217 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1218 tosend[i] = av_lfg_get(&rnd) >> 24;
1220 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1221 /* When the client wants to use RTMPE, we have to change the command
1222 * byte to 0x06 which means to use encrypted data and we have to set
1223 * the flash version to at least 9.0.115.0. */
1230 /* Initialize the Diffie-Hellmann context and generate the public key
1231 * to send to the server. */
1232 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1236 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1240 if ((ret = ffurl_write(rt->stream, tosend,
1241 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1242 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1246 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1247 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1248 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1252 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1253 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1254 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1258 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1259 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1260 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1262 if (rt->is_input && serverdata[5] >= 3) {
1263 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1269 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1274 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1275 return AVERROR(EIO);
1279 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1280 * key are the last 32 bytes of the server handshake. */
1282 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1283 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1287 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1288 rtmp_server_key, sizeof(rtmp_server_key),
1293 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1294 0, digest, 32, signature);
1298 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1299 /* Compute the shared secret key sent by the server and initialize
1300 * the RC4 encryption. */
1301 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1302 tosend + 1, type)) < 0)
1305 /* Encrypt the signature received by the server. */
1306 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1309 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1310 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1311 return AVERROR(EIO);
1314 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1315 tosend[i] = av_lfg_get(&rnd) >> 24;
1316 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1317 rtmp_player_key, sizeof(rtmp_player_key),
1322 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1324 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1328 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1329 /* Encrypt the signature to be send to the server. */
1330 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1331 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1335 // write reply back to the server
1336 if ((ret = ffurl_write(rt->stream, tosend,
1337 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1340 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1341 /* Set RC4 keys for encryption and update the keystreams. */
1342 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1346 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1347 /* Compute the shared secret key sent by the server and initialize
1348 * the RC4 encryption. */
1349 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1350 tosend + 1, 1)) < 0)
1353 if (serverdata[0] == 9) {
1354 /* Encrypt the signature received by the server. */
1355 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1360 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1361 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1364 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1365 /* Set RC4 keys for encryption and update the keystreams. */
1366 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1374 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1375 uint32_t *second_int, char *arraydata,
1380 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1381 RTMP_HANDSHAKE_PACKET_SIZE);
1383 return AVERROR(EIO);
1384 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1385 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1386 " not following standard\n", (int)inoutsize);
1387 return AVERROR(EINVAL);
1390 *first_int = AV_RB32(arraydata);
1391 *second_int = AV_RB32(arraydata + 4);
1395 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1396 uint32_t second_int, char *arraydata, int size)
1400 AV_WB32(arraydata, first_int);
1401 AV_WB32(arraydata + 4, second_int);
1402 inoutsize = ffurl_write(rt->stream, arraydata,
1403 RTMP_HANDSHAKE_PACKET_SIZE);
1404 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1405 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1406 return AVERROR(EIO);
1413 * rtmp handshake server side
1415 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1417 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1419 uint32_t hs_my_epoch;
1420 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1421 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1428 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1429 if (inoutsize <= 0) {
1430 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1431 return AVERROR(EIO);
1434 if (buffer[0] != 3) {
1435 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1436 return AVERROR(EIO);
1438 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1439 av_log(s, AV_LOG_ERROR,
1440 "Unable to write answer - RTMP S0\n");
1441 return AVERROR(EIO);
1444 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1445 RTMP_HANDSHAKE_PACKET_SIZE);
1447 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1451 /* By now same epoch will be sent */
1452 hs_my_epoch = hs_epoch;
1453 /* Generate random */
1454 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1456 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1458 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1459 RTMP_HANDSHAKE_PACKET_SIZE);
1461 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1465 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1466 RTMP_HANDSHAKE_PACKET_SIZE);
1468 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1472 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1473 RTMP_HANDSHAKE_PACKET_SIZE);
1475 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1478 if (temp != hs_my_epoch)
1479 av_log(s, AV_LOG_WARNING,
1480 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1481 if (memcmp(buffer + 8, hs_s1 + 8,
1482 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1483 av_log(s, AV_LOG_WARNING,
1484 "Erroneous C2 Message random does not match up\n");
1489 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1491 RTMPContext *rt = s->priv_data;
1494 if (pkt->size < 4) {
1495 av_log(s, AV_LOG_ERROR,
1496 "Too short chunk size change packet (%d)\n",
1498 return AVERROR_INVALIDDATA;
1501 if (!rt->is_input) {
1502 /* Send the same chunk size change packet back to the server,
1503 * setting the outgoing chunk size to the same as the incoming one. */
1504 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1505 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1507 rt->out_chunk_size = AV_RB32(pkt->data);
1510 rt->in_chunk_size = AV_RB32(pkt->data);
1511 if (rt->in_chunk_size <= 0) {
1512 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1514 return AVERROR_INVALIDDATA;
1516 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1522 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1524 RTMPContext *rt = s->priv_data;
1527 if (pkt->size < 2) {
1528 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1530 return AVERROR_INVALIDDATA;
1533 t = AV_RB16(pkt->data);
1535 if ((ret = gen_pong(s, rt, pkt)) < 0)
1537 } else if (t == 26) {
1539 if ((ret = gen_swf_verification(s, rt)) < 0)
1542 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1549 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1551 RTMPContext *rt = s->priv_data;
1553 if (pkt->size < 4) {
1554 av_log(s, AV_LOG_ERROR,
1555 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1557 return AVERROR_INVALIDDATA;
1560 rt->client_report_size = AV_RB32(pkt->data);
1561 if (rt->client_report_size <= 0) {
1562 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1563 rt->client_report_size);
1564 return AVERROR_INVALIDDATA;
1567 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1568 rt->client_report_size >>= 1;
1573 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1575 RTMPContext *rt = s->priv_data;
1577 if (pkt->size < 4) {
1578 av_log(s, AV_LOG_ERROR,
1579 "Too short server bandwidth report packet (%d)\n",
1581 return AVERROR_INVALIDDATA;
1584 rt->server_bw = AV_RB32(pkt->data);
1585 if (rt->server_bw <= 0) {
1586 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1588 return AVERROR_INVALIDDATA;
1590 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1595 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1596 const char *opaque, const char *challenge)
1599 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1600 struct AVMD5 *md5 = av_md5_alloc();
1602 return AVERROR(ENOMEM);
1604 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1607 av_md5_update(md5, user, strlen(user));
1608 av_md5_update(md5, salt, strlen(salt));
1609 av_md5_update(md5, rt->password, strlen(rt->password));
1610 av_md5_final(md5, hash);
1611 av_base64_encode(hashstr, sizeof(hashstr), hash,
1614 av_md5_update(md5, hashstr, strlen(hashstr));
1616 av_md5_update(md5, opaque, strlen(opaque));
1618 av_md5_update(md5, challenge, strlen(challenge));
1619 av_md5_update(md5, challenge2, strlen(challenge2));
1620 av_md5_final(md5, hash);
1621 av_base64_encode(hashstr, sizeof(hashstr), hash,
1623 snprintf(rt->auth_params, sizeof(rt->auth_params),
1624 "?authmod=%s&user=%s&challenge=%s&response=%s",
1625 "adobe", user, challenge2, hashstr);
1627 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1628 "&opaque=%s", opaque);
1634 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1637 char hashstr1[33], hashstr2[33];
1638 const char *realm = "live";
1639 const char *method = "publish";
1640 const char *qop = "auth";
1641 const char *nc = "00000001";
1643 struct AVMD5 *md5 = av_md5_alloc();
1645 return AVERROR(ENOMEM);
1647 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1650 av_md5_update(md5, user, strlen(user));
1651 av_md5_update(md5, ":", 1);
1652 av_md5_update(md5, realm, strlen(realm));
1653 av_md5_update(md5, ":", 1);
1654 av_md5_update(md5, rt->password, strlen(rt->password));
1655 av_md5_final(md5, hash);
1656 ff_data_to_hex(hashstr1, hash, 16, 1);
1657 hashstr1[32] = '\0';
1660 av_md5_update(md5, method, strlen(method));
1661 av_md5_update(md5, ":/", 2);
1662 av_md5_update(md5, rt->app, strlen(rt->app));
1663 if (!strchr(rt->app, '/'))
1664 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1665 av_md5_final(md5, hash);
1666 ff_data_to_hex(hashstr2, hash, 16, 1);
1667 hashstr2[32] = '\0';
1670 av_md5_update(md5, hashstr1, strlen(hashstr1));
1671 av_md5_update(md5, ":", 1);
1673 av_md5_update(md5, nonce, strlen(nonce));
1674 av_md5_update(md5, ":", 1);
1675 av_md5_update(md5, nc, strlen(nc));
1676 av_md5_update(md5, ":", 1);
1677 av_md5_update(md5, cnonce, strlen(cnonce));
1678 av_md5_update(md5, ":", 1);
1679 av_md5_update(md5, qop, strlen(qop));
1680 av_md5_update(md5, ":", 1);
1681 av_md5_update(md5, hashstr2, strlen(hashstr2));
1682 av_md5_final(md5, hash);
1683 ff_data_to_hex(hashstr1, hash, 16, 1);
1685 snprintf(rt->auth_params, sizeof(rt->auth_params),
1686 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1687 "llnw", user, nonce, cnonce, nc, hashstr1);
1693 static int handle_connect_error(URLContext *s, const char *desc)
1695 RTMPContext *rt = s->priv_data;
1696 char buf[300], *ptr, authmod[15];
1698 const char *user = "", *salt = "", *opaque = NULL,
1699 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1701 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1702 !(cptr = strstr(desc, "authmod=llnw"))) {
1703 av_log(s, AV_LOG_ERROR,
1704 "Unknown connect error (unsupported authentication method?)\n");
1705 return AVERROR_UNKNOWN;
1707 cptr += strlen("authmod=");
1708 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1709 authmod[i++] = *cptr++;
1712 if (!rt->username[0] || !rt->password[0]) {
1713 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1714 return AVERROR_UNKNOWN;
1717 if (strstr(desc, "?reason=authfailed")) {
1718 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1719 return AVERROR_UNKNOWN;
1720 } else if (strstr(desc, "?reason=nosuchuser")) {
1721 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1722 return AVERROR_UNKNOWN;
1725 if (rt->auth_tried) {
1726 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1727 return AVERROR_UNKNOWN;
1730 rt->auth_params[0] = '\0';
1732 if (strstr(desc, "code=403 need auth")) {
1733 snprintf(rt->auth_params, sizeof(rt->auth_params),
1734 "?authmod=%s&user=%s", authmod, rt->username);
1738 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1739 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1740 return AVERROR_UNKNOWN;
1743 av_strlcpy(buf, cptr + 1, sizeof(buf));
1747 char *next = strchr(ptr, '&');
1748 char *value = strchr(ptr, '=');
1753 if (!strcmp(ptr, "user")) {
1755 } else if (!strcmp(ptr, "salt")) {
1757 } else if (!strcmp(ptr, "opaque")) {
1759 } else if (!strcmp(ptr, "challenge")) {
1761 } else if (!strcmp(ptr, "nonce")) {
1767 if (!strcmp(authmod, "adobe")) {
1768 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1771 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1779 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1781 RTMPContext *rt = s->priv_data;
1782 const uint8_t *data_end = pkt->data + pkt->size;
1783 char *tracked_method = NULL;
1784 int level = AV_LOG_ERROR;
1785 uint8_t tmpstr[256];
1788 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1791 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1792 "description", tmpstr, sizeof(tmpstr))) {
1793 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1794 !strcmp(tracked_method, "releaseStream") ||
1795 !strcmp(tracked_method, "FCSubscribe") ||
1796 !strcmp(tracked_method, "FCPublish"))) {
1797 /* Gracefully ignore Adobe-specific historical artifact errors. */
1798 level = AV_LOG_WARNING;
1800 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1801 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1803 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1804 ret = handle_connect_error(s, tmpstr);
1806 rt->do_reconnect = 1;
1807 level = AV_LOG_VERBOSE;
1810 ret = AVERROR_UNKNOWN;
1811 av_log(s, level, "Server error: %s\n", tmpstr);
1814 av_free(tracked_method);
1818 static int write_begin(URLContext *s)
1820 RTMPContext *rt = s->priv_data;
1822 RTMPPacket spkt = { 0 };
1825 // Send Stream Begin 1
1826 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1827 RTMP_PT_PING, 0, 6)) < 0) {
1828 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1832 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1833 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1834 bytestream2_put_be32(&pbc, rt->nb_streamid);
1836 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1837 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1839 ff_rtmp_packet_destroy(&spkt);
1844 static int write_status(URLContext *s, RTMPPacket *pkt,
1845 const char *status, const char *filename)
1847 RTMPContext *rt = s->priv_data;
1848 RTMPPacket spkt = { 0 };
1849 char statusmsg[128];
1853 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1855 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1856 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1861 spkt.extra = pkt->extra;
1862 ff_amf_write_string(&pp, "onStatus");
1863 ff_amf_write_number(&pp, 0);
1864 ff_amf_write_null(&pp);
1866 ff_amf_write_object_start(&pp);
1867 ff_amf_write_field_name(&pp, "level");
1868 ff_amf_write_string(&pp, "status");
1869 ff_amf_write_field_name(&pp, "code");
1870 ff_amf_write_string(&pp, status);
1871 ff_amf_write_field_name(&pp, "description");
1872 snprintf(statusmsg, sizeof(statusmsg),
1873 "%s is now published", filename);
1874 ff_amf_write_string(&pp, statusmsg);
1875 ff_amf_write_field_name(&pp, "details");
1876 ff_amf_write_string(&pp, filename);
1877 ff_amf_write_field_name(&pp, "clientid");
1878 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1879 ff_amf_write_string(&pp, statusmsg);
1880 ff_amf_write_object_end(&pp);
1882 spkt.size = pp - spkt.data;
1883 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1884 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1885 ff_rtmp_packet_destroy(&spkt);
1890 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1892 RTMPContext *rt = s->priv_data;
1898 const uint8_t *p = pkt->data;
1900 RTMPPacket spkt = { 0 };
1904 bytestream2_init(&gbc, p, pkt->size);
1905 if (ff_amf_read_string(&gbc, command, sizeof(command),
1907 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1908 return AVERROR_INVALIDDATA;
1911 ret = ff_amf_read_number(&gbc, &seqnum);
1914 ret = ff_amf_read_null(&gbc);
1917 if (!strcmp(command, "FCPublish") ||
1918 !strcmp(command, "publish")) {
1919 ret = ff_amf_read_string(&gbc, filename,
1920 sizeof(filename), &stringlen);
1922 if (ret == AVERROR(EINVAL))
1923 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
1925 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
1930 pchar = strrchr(s->filename, '/');
1932 av_log(s, AV_LOG_WARNING,
1933 "Unable to find / in url %s, bad format\n",
1935 pchar = s->filename;
1938 if (strcmp(pchar, filename))
1939 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1940 " %s\n", filename, pchar);
1942 rt->state = STATE_RECEIVING;
1945 if (!strcmp(command, "FCPublish")) {
1946 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1948 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1949 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1953 ff_amf_write_string(&pp, "onFCPublish");
1954 } else if (!strcmp(command, "publish")) {
1955 ret = write_begin(s);
1959 // Send onStatus(NetStream.Publish.Start)
1960 return write_status(s, pkt, "NetStream.Publish.Start",
1962 } else if (!strcmp(command, "play")) {
1963 ret = write_begin(s);
1966 rt->state = STATE_SENDING;
1967 return write_status(s, pkt, "NetStream.Play.Start",
1970 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1972 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1973 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1977 ff_amf_write_string(&pp, "_result");
1978 ff_amf_write_number(&pp, seqnum);
1979 ff_amf_write_null(&pp);
1980 if (!strcmp(command, "createStream")) {
1982 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1983 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1984 ff_amf_write_number(&pp, rt->nb_streamid);
1985 /* By now we don't control which streams are removed in
1986 * deleteStream. There is no stream creation control
1987 * if a client creates more than 2^32 - 2 streams. */
1990 spkt.size = pp - spkt.data;
1991 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1992 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1993 ff_rtmp_packet_destroy(&spkt);
1998 * Read the AMF_NUMBER response ("_result") to a function call
1999 * (e.g. createStream()). This response should be made up of the AMF_STRING
2000 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2001 * successful response, we will return set the value to number (otherwise number
2002 * will not be changed).
2004 * @return 0 if reading the value succeeds, negative value otherwise
2006 static int read_number_result(RTMPPacket *pkt, double *number)
2008 // We only need to fit "_result" in this.
2009 uint8_t strbuffer[8];
2014 bytestream2_init(&gbc, pkt->data, pkt->size);
2016 // Value 1/4: "_result" as AMF_STRING
2017 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2018 return AVERROR_INVALIDDATA;
2019 if (strcmp(strbuffer, "_result"))
2020 return AVERROR_INVALIDDATA;
2021 // Value 2/4: The callee reference number
2022 if (ff_amf_read_number(&gbc, &numbuffer))
2023 return AVERROR_INVALIDDATA;
2025 if (ff_amf_read_null(&gbc))
2026 return AVERROR_INVALIDDATA;
2027 // Value 4/4: The response as AMF_NUMBER
2028 if (ff_amf_read_number(&gbc, &numbuffer))
2029 return AVERROR_INVALIDDATA;
2031 *number = numbuffer;
2036 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2038 RTMPContext *rt = s->priv_data;
2039 char *tracked_method = NULL;
2042 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2045 if (!tracked_method) {
2046 /* Ignore this reply when the current method is not tracked. */
2050 if (!strcmp(tracked_method, "connect")) {
2051 if (!rt->is_input) {
2052 if ((ret = gen_release_stream(s, rt)) < 0)
2055 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2058 if ((ret = gen_server_bw(s, rt)) < 0)
2062 if ((ret = gen_create_stream(s, rt)) < 0)
2066 /* Send the FCSubscribe command when the name of live
2067 * stream is defined by the user or if it's a live stream. */
2068 if (rt->subscribe) {
2069 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2071 } else if (rt->live == -1) {
2072 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2076 } else if (!strcmp(tracked_method, "createStream")) {
2078 if (read_number_result(pkt, &stream_id)) {
2079 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2081 rt->stream_id = stream_id;
2084 if (!rt->is_input) {
2085 if ((ret = gen_publish(s, rt)) < 0)
2088 if (rt->live != -1) {
2089 if ((ret = gen_get_stream_length(s, rt)) < 0)
2092 if ((ret = gen_play(s, rt)) < 0)
2094 if ((ret = gen_buffer_time(s, rt)) < 0)
2097 } else if (!strcmp(tracked_method, "getStreamLength")) {
2098 if (read_number_result(pkt, &rt->duration)) {
2099 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2104 av_free(tracked_method);
2108 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2110 RTMPContext *rt = s->priv_data;
2111 const uint8_t *data_end = pkt->data + pkt->size;
2112 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2113 uint8_t tmpstr[256];
2116 for (i = 0; i < 2; i++) {
2117 t = ff_amf_tag_size(ptr, data_end);
2123 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2124 if (!t && !strcmp(tmpstr, "error")) {
2125 t = ff_amf_get_field_value(ptr, data_end,
2126 "description", tmpstr, sizeof(tmpstr));
2127 if (t || !tmpstr[0])
2128 t = ff_amf_get_field_value(ptr, data_end, "code",
2129 tmpstr, sizeof(tmpstr));
2131 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2135 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2136 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2137 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2138 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2139 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2140 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2145 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2147 RTMPContext *rt = s->priv_data;
2150 //TODO: check for the messages sent for wrong state?
2151 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2152 if ((ret = handle_invoke_error(s, pkt)) < 0)
2154 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2155 if ((ret = handle_invoke_result(s, pkt)) < 0)
2157 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2158 if ((ret = handle_invoke_status(s, pkt)) < 0)
2160 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2161 if ((ret = gen_check_bw(s, rt)) < 0)
2163 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2164 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2165 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2166 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2167 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2168 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2169 if ((ret = send_invoke_response(s, pkt)) < 0)
2176 static int update_offset(RTMPContext *rt, int size)
2180 // generate packet header and put data into buffer for FLV demuxer
2181 if (rt->flv_off < rt->flv_size) {
2182 // There is old unread data in the buffer, thus append at the end
2183 old_flv_size = rt->flv_size;
2184 rt->flv_size += size;
2186 // All data has been read, write the new data at the start of the buffer
2188 rt->flv_size = size;
2192 return old_flv_size;
2195 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2197 int old_flv_size, ret;
2199 const uint8_t *data = pkt->data + skip;
2200 const int size = pkt->size - skip;
2201 uint32_t ts = pkt->timestamp;
2203 if (pkt->type == RTMP_PT_AUDIO) {
2205 } else if (pkt->type == RTMP_PT_VIDEO) {
2209 old_flv_size = update_offset(rt, size + 15);
2211 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2212 rt->flv_size = rt->flv_off = 0;
2215 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2216 bytestream2_skip_p(&pbc, old_flv_size);
2217 bytestream2_put_byte(&pbc, pkt->type);
2218 bytestream2_put_be24(&pbc, size);
2219 bytestream2_put_be24(&pbc, ts);
2220 bytestream2_put_byte(&pbc, ts >> 24);
2221 bytestream2_put_be24(&pbc, 0);
2222 bytestream2_put_buffer(&pbc, data, size);
2223 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2228 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2230 RTMPContext *rt = s->priv_data;
2231 uint8_t commandbuffer[64];
2232 char statusmsg[128];
2233 int stringlen, ret, skip = 0;
2236 bytestream2_init(&gbc, pkt->data, pkt->size);
2237 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2239 return AVERROR_INVALIDDATA;
2241 if (!strcmp(commandbuffer, "onMetaData")) {
2242 // metadata properties should be stored in a mixed array
2243 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2244 // We have found a metaData Array so flv can determine the streams
2246 rt->received_metadata = 1;
2247 // skip 32-bit max array index
2248 bytestream2_skip(&gbc, 4);
2249 while (bytestream2_get_bytes_left(&gbc) > 3) {
2250 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2252 return AVERROR_INVALIDDATA;
2253 // We do not care about the content of the property (yet).
2254 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2256 return AVERROR_INVALIDDATA;
2257 bytestream2_skip(&gbc, stringlen);
2259 // The presence of the following properties indicates that the
2260 // respective streams are present.
2261 if (!strcmp(statusmsg, "videocodecid")) {
2264 if (!strcmp(statusmsg, "audiocodecid")) {
2268 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2269 return AVERROR_INVALIDDATA;
2273 // Skip the @setDataFrame string and validate it is a notification
2274 if (!strcmp(commandbuffer, "@setDataFrame")) {
2275 skip = gbc.buffer - pkt->data;
2276 ret = ff_amf_read_string(&gbc, statusmsg,
2277 sizeof(statusmsg), &stringlen);
2279 return AVERROR_INVALIDDATA;
2282 return append_flv_data(rt, pkt, skip);
2286 * Parse received packet and possibly perform some action depending on
2287 * the packet contents.
2288 * @return 0 for no errors, negative values for serious errors which prevent
2289 * further communications, positive values for uncritical errors
2291 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2296 ff_rtmp_packet_dump(s, pkt);
2299 switch (pkt->type) {
2300 case RTMP_PT_BYTES_READ:
2301 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2303 case RTMP_PT_CHUNK_SIZE:
2304 if ((ret = handle_chunk_size(s, pkt)) < 0)
2308 if ((ret = handle_ping(s, pkt)) < 0)
2311 case RTMP_PT_CLIENT_BW:
2312 if ((ret = handle_client_bw(s, pkt)) < 0)
2315 case RTMP_PT_SERVER_BW:
2316 if ((ret = handle_server_bw(s, pkt)) < 0)
2319 case RTMP_PT_INVOKE:
2320 if ((ret = handle_invoke(s, pkt)) < 0)
2325 case RTMP_PT_METADATA:
2326 case RTMP_PT_NOTIFY:
2327 /* Audio, Video and Metadata packets are parsed in get_packet() */
2330 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2336 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2338 int ret, old_flv_size, type;
2339 const uint8_t *next;
2342 uint32_t ts, cts, pts = 0;
2344 old_flv_size = update_offset(rt, pkt->size);
2346 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2347 rt->flv_size = rt->flv_off = 0;
2352 p = rt->flv_data + old_flv_size;
2354 /* copy data while rewriting timestamps */
2355 ts = pkt->timestamp;
2357 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2358 type = bytestream_get_byte(&next);
2359 size = bytestream_get_be24(&next);
2360 cts = bytestream_get_be24(&next);
2361 cts |= bytestream_get_byte(&next) << 24;
2366 if (size + 3 + 4 > pkt->data + pkt->size - next)
2368 bytestream_put_byte(&p, type);
2369 bytestream_put_be24(&p, size);
2370 bytestream_put_be24(&p, ts);
2371 bytestream_put_byte(&p, ts >> 24);
2372 memcpy(p, next, size + 3 + 4);
2374 bytestream_put_be32(&p, size + RTMP_HEADER);
2375 next += size + 3 + 4;
2377 if (p != rt->flv_data + rt->flv_size) {
2378 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2379 "RTMP_PT_METADATA packet\n");
2380 rt->flv_size = p - rt->flv_data;
2387 * Interact with the server by receiving and sending RTMP packets until
2388 * there is some significant data (media data or expected status notification).
2390 * @param s reading context
2391 * @param for_header non-zero value tells function to work until it
2392 * gets notification from the server that playing has been started,
2393 * otherwise function will work until some media data is received (or
2395 * @return 0 for successful operation, negative value in case of error
2397 static int get_packet(URLContext *s, int for_header)
2399 RTMPContext *rt = s->priv_data;
2402 if (rt->state == STATE_STOPPED)
2406 RTMPPacket rpkt = { 0 };
2407 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2408 rt->in_chunk_size, &rt->prev_pkt[0],
2409 &rt->nb_prev_pkt[0])) <= 0) {
2411 return AVERROR(EAGAIN);
2413 return AVERROR(EIO);
2417 // Track timestamp for later use
2418 rt->last_timestamp = rpkt.timestamp;
2420 rt->bytes_read += ret;
2421 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
2422 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2423 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2425 rt->last_bytes_read = rt->bytes_read;
2428 ret = rtmp_parse_result(s, rt, &rpkt);
2430 // At this point we must check if we are in the seek state and continue
2431 // with the next packet. handle_invoke will get us out of this state
2432 // when the right message is encountered
2433 if (rt->state == STATE_SEEKING) {
2434 ff_rtmp_packet_destroy(&rpkt);
2435 // We continue, let the natural flow of things happen:
2436 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2440 if (ret < 0) {//serious error in current packet
2441 ff_rtmp_packet_destroy(&rpkt);
2444 if (rt->do_reconnect && for_header) {
2445 ff_rtmp_packet_destroy(&rpkt);
2448 if (rt->state == STATE_STOPPED) {
2449 ff_rtmp_packet_destroy(&rpkt);
2452 if (for_header && (rt->state == STATE_PLAYING ||
2453 rt->state == STATE_PUBLISHING ||
2454 rt->state == STATE_SENDING ||
2455 rt->state == STATE_RECEIVING)) {
2456 ff_rtmp_packet_destroy(&rpkt);
2459 if (!rpkt.size || !rt->is_input) {
2460 ff_rtmp_packet_destroy(&rpkt);
2463 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2464 ret = append_flv_data(rt, &rpkt, 0);
2465 ff_rtmp_packet_destroy(&rpkt);
2467 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2468 ret = handle_notify(s, &rpkt);
2469 ff_rtmp_packet_destroy(&rpkt);
2471 } else if (rpkt.type == RTMP_PT_METADATA) {
2472 ret = handle_metadata(rt, &rpkt);
2473 ff_rtmp_packet_destroy(&rpkt);
2476 ff_rtmp_packet_destroy(&rpkt);
2480 static int rtmp_close(URLContext *h)
2482 RTMPContext *rt = h->priv_data;
2485 if (!rt->is_input) {
2486 rt->flv_data = NULL;
2487 if (rt->out_pkt.size)
2488 ff_rtmp_packet_destroy(&rt->out_pkt);
2489 if (rt->state > STATE_FCPUBLISH)
2490 ret = gen_fcunpublish_stream(h, rt);
2492 if (rt->state > STATE_HANDSHAKED)
2493 ret = gen_delete_stream(h, rt);
2494 for (i = 0; i < 2; i++) {
2495 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2496 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2497 av_freep(&rt->prev_pkt[i]);
2500 free_tracked_methods(rt);
2501 av_freep(&rt->flv_data);
2502 ffurl_close(rt->stream);
2507 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2508 * demuxer about the duration of the stream.
2510 * This should only be done if there was no real onMetadata packet sent by the
2511 * server at the start of the stream and if we were able to retrieve a valid
2512 * duration via a getStreamLength call.
2514 * @return 0 for successful operation, negative value in case of error
2516 static int inject_fake_duration_metadata(RTMPContext *rt)
2518 // We need to insert the metadata packet directly after the FLV
2519 // header, i.e. we need to move all other already read data by the
2520 // size of our fake metadata packet.
2523 // Keep old flv_data pointer
2524 uint8_t* old_flv_data = rt->flv_data;
2525 // Allocate a new flv_data pointer with enough space for the additional package
2526 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2527 rt->flv_data = old_flv_data;
2528 return AVERROR(ENOMEM);
2532 memcpy(rt->flv_data, old_flv_data, 13);
2533 // Copy remaining packets
2534 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2535 // Increase the size by the injected packet
2537 // Delete the old FLV data
2538 av_free(old_flv_data);
2540 p = rt->flv_data + 13;
2541 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2542 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2543 bytestream_put_be24(&p, 0); // timestamp
2544 bytestream_put_be32(&p, 0); // reserved
2546 // first event name as a string
2547 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2548 // "onMetaData" as AMF string
2549 bytestream_put_be16(&p, 10);
2550 bytestream_put_buffer(&p, "onMetaData", 10);
2552 // mixed array (hash) with size and string/type/data tuples
2553 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2554 bytestream_put_be32(&p, 1); // metadata_count
2556 // "duration" as AMF string
2557 bytestream_put_be16(&p, 8);
2558 bytestream_put_buffer(&p, "duration", 8);
2559 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2560 bytestream_put_be64(&p, av_double2int(rt->duration));
2563 bytestream_put_be16(&p, 0); // Empty string
2564 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2565 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2571 * Open RTMP connection and verify that the stream can be played.
2573 * URL syntax: rtmp://server[:port][/app][/playpath]
2574 * where 'app' is first one or two directories in the path
2575 * (e.g. /ondemand/, /flash/live/, etc.)
2576 * and 'playpath' is a file name (the rest of the path,
2577 * may be prefixed with "mp4:")
2579 static int rtmp_open(URLContext *s, const char *uri, int flags)
2581 RTMPContext *rt = s->priv_data;
2582 char proto[8], hostname[256], path[1024], auth[100], *fname;
2583 char *old_app, *qmark, fname_buffer[1024];
2586 AVDictionary *opts = NULL;
2589 if (rt->listen_timeout > 0)
2592 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2594 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2595 hostname, sizeof(hostname), &port,
2596 path, sizeof(path), s->filename);
2598 if (strchr(path, ' ')) {
2599 av_log(s, AV_LOG_WARNING,
2600 "Detected librtmp style URL parameters, these aren't supported "
2601 "by the libavformat internal RTMP handler currently enabled. "
2602 "See the documentation for the correct way to pass parameters.\n");
2606 char *ptr = strchr(auth, ':');
2609 av_strlcpy(rt->username, auth, sizeof(rt->username));
2610 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2614 if (rt->listen && strcmp(proto, "rtmp")) {
2615 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2617 return AVERROR(EINVAL);
2619 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2620 if (!strcmp(proto, "rtmpts"))
2621 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2623 /* open the http tunneling connection */
2624 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2625 } else if (!strcmp(proto, "rtmps")) {
2626 /* open the tls connection */
2628 port = RTMPS_DEFAULT_PORT;
2629 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2630 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2631 if (!strcmp(proto, "rtmpte"))
2632 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2634 /* open the encrypted connection */
2635 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2638 /* open the tcp connection */
2640 port = RTMP_DEFAULT_PORT;
2642 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2643 "?listen&listen_timeout=%d",
2644 rt->listen_timeout * 1000);
2646 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2650 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2651 &s->interrupt_callback, &opts, s->protocols, s)) < 0) {
2652 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2656 if (rt->swfverify) {
2657 if ((ret = rtmp_calc_swfhash(s)) < 0)
2661 rt->state = STATE_START;
2662 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2664 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2667 rt->out_chunk_size = 128;
2668 rt->in_chunk_size = 128; // Probably overwritten later
2669 rt->state = STATE_HANDSHAKED;
2671 // Keep the application name when it has been defined by the user.
2674 rt->app = av_malloc(APP_MAX_LENGTH);
2676 ret = AVERROR(ENOMEM);
2680 //extract "app" part from path
2681 qmark = strchr(path, '?');
2682 if (qmark && strstr(qmark, "slist=")) {
2684 // After slist we have the playpath, the full path is used as app
2685 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2686 fname = strstr(path, "slist=") + 6;
2687 // Strip any further query parameters from fname
2688 amp = strchr(fname, '&');
2690 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2691 sizeof(fname_buffer)));
2692 fname = fname_buffer;
2694 } else if (!strncmp(path, "/ondemand/", 10)) {
2696 memcpy(rt->app, "ondemand", 9);
2698 char *next = *path ? path + 1 : path;
2699 char *p = strchr(next, '/');
2704 // make sure we do not mismatch a playpath for an application instance
2705 char *c = strchr(p + 1, ':');
2706 fname = strchr(p + 1, '/');
2707 if (!fname || (c && c < fname)) {
2709 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2712 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2718 // The name of application has been defined by the user, override it.
2723 if (!rt->playpath) {
2724 int len = strlen(fname);
2726 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2727 if (!rt->playpath) {
2728 ret = AVERROR(ENOMEM);
2732 if (!strchr(fname, ':') && len >= 4 &&
2733 (!strcmp(fname + len - 4, ".f4v") ||
2734 !strcmp(fname + len - 4, ".mp4"))) {
2735 memcpy(rt->playpath, "mp4:", 5);
2737 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2738 fname[len - 4] = '\0';
2739 rt->playpath[0] = 0;
2741 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2745 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2747 ret = AVERROR(ENOMEM);
2750 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2751 port, "/%s", rt->app);
2754 if (!rt->flashver) {
2755 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2756 if (!rt->flashver) {
2757 ret = AVERROR(ENOMEM);
2761 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2762 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2763 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2765 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2766 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2770 rt->client_report_size = 1048576;
2774 rt->received_metadata = 0;
2775 rt->last_bytes_read = 0;
2776 rt->server_bw = 2500000;
2779 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2780 proto, path, rt->app, rt->playpath);
2782 if ((ret = gen_connect(s, rt)) < 0)
2785 if ((ret = read_connect(s, s->priv_data)) < 0)
2790 ret = get_packet(s, 1);
2791 } while (ret == AVERROR(EAGAIN));
2795 if (rt->do_reconnect) {
2797 ffurl_close(rt->stream);
2799 rt->do_reconnect = 0;
2801 for (i = 0; i < 2; i++)
2802 memset(rt->prev_pkt[i], 0,
2803 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2804 free_tracked_methods(rt);
2809 // generate FLV header for demuxer
2811 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2814 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2816 // Read packets until we reach the first A/V packet or read metadata.
2817 // If there was a metadata package in front of the A/V packets, we can
2818 // build the FLV header from this. If we do not receive any metadata,
2819 // the FLV decoder will allocate the needed streams when their first
2820 // audio or video packet arrives.
2821 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2822 if ((ret = get_packet(s, 0)) < 0)
2826 // Either after we have read the metadata or (if there is none) the
2827 // first packet of an A/V stream, we have a better knowledge about the
2828 // streams, so set the FLV header accordingly.
2829 if (rt->has_audio) {
2830 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2832 if (rt->has_video) {
2833 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2836 // If we received the first packet of an A/V stream and no metadata but
2837 // the server returned a valid duration, create a fake metadata packet
2838 // to inform the FLV decoder about the duration.
2839 if (!rt->received_metadata && rt->duration > 0) {
2840 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2845 rt->flv_data = NULL;
2847 rt->skip_bytes = 13;
2850 s->max_packet_size = rt->stream->max_packet_size;
2855 av_dict_free(&opts);
2860 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2862 RTMPContext *rt = s->priv_data;
2863 int orig_size = size;
2867 int data_left = rt->flv_size - rt->flv_off;
2869 if (data_left >= size) {
2870 memcpy(buf, rt->flv_data + rt->flv_off, size);
2871 rt->flv_off += size;
2874 if (data_left > 0) {
2875 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2878 rt->flv_off = rt->flv_size;
2881 if ((ret = get_packet(s, 0)) < 0)
2887 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2890 RTMPContext *rt = s->priv_data;
2892 av_log(s, AV_LOG_DEBUG,
2893 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2894 stream_index, timestamp, flags);
2895 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2896 av_log(s, AV_LOG_ERROR,
2897 "Unable to send seek command on stream index %d at timestamp "
2898 "%"PRId64" with flags %08x\n",
2899 stream_index, timestamp, flags);
2902 rt->flv_off = rt->flv_size;
2903 rt->state = STATE_SEEKING;
2907 static int rtmp_pause(URLContext *s, int pause)
2909 RTMPContext *rt = s->priv_data;
2911 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2912 rt->last_timestamp);
2913 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2914 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2915 rt->last_timestamp);
2921 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2923 RTMPContext *rt = s->priv_data;
2924 int size_temp = size;
2925 int pktsize, pkttype, copy;
2927 const uint8_t *buf_temp = buf;
2932 if (rt->skip_bytes) {
2933 int skip = FFMIN(rt->skip_bytes, size_temp);
2936 rt->skip_bytes -= skip;
2940 if (rt->flv_header_bytes < RTMP_HEADER) {
2941 const uint8_t *header = rt->flv_header;
2942 int channel = RTMP_AUDIO_CHANNEL;
2943 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2944 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2945 rt->flv_header_bytes += copy;
2947 if (rt->flv_header_bytes < RTMP_HEADER)
2950 pkttype = bytestream_get_byte(&header);
2951 pktsize = bytestream_get_be24(&header);
2952 ts = bytestream_get_be24(&header);
2953 ts |= bytestream_get_byte(&header) << 24;
2954 bytestream_get_be24(&header);
2955 rt->flv_size = pktsize;
2957 if (pkttype == RTMP_PT_VIDEO)
2958 channel = RTMP_VIDEO_CHANNEL;
2960 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2961 pkttype == RTMP_PT_NOTIFY) {
2962 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2963 &rt->nb_prev_pkt[1],
2966 // Force sending a full 12 bytes header by clearing the
2967 // channel id, to make it not match a potential earlier
2968 // packet in the same channel.
2969 rt->prev_pkt[1][channel].channel_id = 0;
2972 //this can be a big packet, it's better to send it right here
2973 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2974 pkttype, ts, pktsize)) < 0)
2977 rt->out_pkt.extra = rt->stream_id;
2978 rt->flv_data = rt->out_pkt.data;
2981 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
2982 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
2983 rt->flv_off += copy;
2986 if (rt->flv_off == rt->flv_size) {
2989 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
2990 // For onMetaData and |RtmpSampleAccess packets, we want
2991 // @setDataFrame prepended to the packet before it gets sent.
2992 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
2994 uint8_t commandbuffer[64];
2998 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
2999 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3001 if (!strcmp(commandbuffer, "onMetaData") ||
3002 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3004 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3005 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3008 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3009 rt->out_pkt.size += 16;
3010 ptr = rt->out_pkt.data;
3011 ff_amf_write_string(&ptr, "@setDataFrame");
3016 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3020 rt->flv_header_bytes = 0;
3021 rt->flv_nb_packets++;
3023 } while (buf_temp - buf < size);
3025 if (rt->flv_nb_packets < rt->flush_interval)
3027 rt->flv_nb_packets = 0;
3029 /* set stream into nonblocking mode */
3030 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3032 /* try to read one byte from the stream */
3033 ret = ffurl_read(rt->stream, &c, 1);
3035 /* switch the stream back into blocking mode */
3036 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3038 if (ret == AVERROR(EAGAIN)) {
3039 /* no incoming data to handle */
3041 } else if (ret < 0) {
3043 } else if (ret == 1) {
3044 RTMPPacket rpkt = { 0 };
3046 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3049 &rt->nb_prev_pkt[0], c)) <= 0)
3052 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3055 ff_rtmp_packet_destroy(&rpkt);
3061 #define OFFSET(x) offsetof(RTMPContext, x)
3062 #define DEC AV_OPT_FLAG_DECODING_PARAM
3063 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3065 static const AVOption rtmp_options[] = {
3066 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3067 {"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},
3068 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3069 {"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},
3070 {"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},
3071 {"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"},
3072 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3073 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3074 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3075 {"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},
3076 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3077 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3078 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3079 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3080 {"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},
3081 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3082 {"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},
3083 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3084 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3085 {"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" },
3089 #define RTMP_PROTOCOL(flavor) \
3090 static const AVClass flavor##_class = { \
3091 .class_name = #flavor, \
3092 .item_name = av_default_item_name, \
3093 .option = rtmp_options, \
3094 .version = LIBAVUTIL_VERSION_INT, \
3097 const URLProtocol ff_##flavor##_protocol = { \
3099 .url_open = rtmp_open, \
3100 .url_read = rtmp_read, \
3101 .url_read_seek = rtmp_seek, \
3102 .url_read_pause = rtmp_pause, \
3103 .url_write = rtmp_write, \
3104 .url_close = rtmp_close, \
3105 .priv_data_size = sizeof(RTMPContext), \
3106 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3107 .priv_data_class= &flavor##_class, \
3112 RTMP_PROTOCOL(rtmpe)
3113 RTMP_PROTOCOL(rtmps)
3114 RTMP_PROTOCOL(rtmpt)
3115 RTMP_PROTOCOL(rtmpte)
3116 RTMP_PROTOCOL(rtmpts)