2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/intfloat.h"
31 #include "libavutil/lfg.h"
32 #include "libavutil/md5.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/random_seed.h"
35 #include "libavutil/sha.h"
43 #include "rtmpcrypt.h"
51 #define APP_MAX_LENGTH 1024
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,
325 0, 4096 + APP_MAX_LENGTH)) < 0)
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)
423 ff_rtmp_packet_destroy(&pkt);
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)
430 bytestream2_init(&gbc, cp, pkt.size);
431 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
432 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
433 ff_rtmp_packet_destroy(&pkt);
434 return AVERROR_INVALIDDATA;
436 if (strcmp(command, "connect")) {
437 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
438 ff_rtmp_packet_destroy(&pkt);
439 return AVERROR_INVALIDDATA;
441 ret = ff_amf_read_number(&gbc, &seqnum);
443 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
444 /* Here one could parse an AMF Object with data as flashVers and others. */
445 ret = ff_amf_get_field_value(gbc.buffer,
446 gbc.buffer + bytestream2_get_bytes_left(&gbc),
447 "app", tmpstr, sizeof(tmpstr));
449 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
450 if (!ret && strcmp(tmpstr, rt->app))
451 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
453 ff_rtmp_packet_destroy(&pkt);
455 // Send Window Acknowledgement Size (as defined in speficication)
456 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
457 RTMP_PT_SERVER_BW, 0, 4)) < 0)
460 bytestream_put_be32(&p, rt->server_bw);
461 pkt.size = p - pkt.data;
462 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
463 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
464 ff_rtmp_packet_destroy(&pkt);
467 // Send Peer Bandwidth
468 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
469 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
472 bytestream_put_be32(&p, rt->server_bw);
473 bytestream_put_byte(&p, 2); // dynamic
474 pkt.size = p - pkt.data;
475 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
476 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
477 ff_rtmp_packet_destroy(&pkt);
482 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
483 RTMP_PT_PING, 0, 6)) < 0)
487 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
488 bytestream_put_be32(&p, 0);
489 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
490 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
491 ff_rtmp_packet_destroy(&pkt);
496 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
497 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
501 bytestream_put_be32(&p, rt->out_chunk_size);
502 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
503 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
504 ff_rtmp_packet_destroy(&pkt);
508 // Send _result NetConnection.Connect.Success to connect
509 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
511 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
515 ff_amf_write_string(&p, "_result");
516 ff_amf_write_number(&p, seqnum);
518 ff_amf_write_object_start(&p);
519 ff_amf_write_field_name(&p, "fmsVer");
520 ff_amf_write_string(&p, "FMS/3,0,1,123");
521 ff_amf_write_field_name(&p, "capabilities");
522 ff_amf_write_number(&p, 31);
523 ff_amf_write_object_end(&p);
525 ff_amf_write_object_start(&p);
526 ff_amf_write_field_name(&p, "level");
527 ff_amf_write_string(&p, "status");
528 ff_amf_write_field_name(&p, "code");
529 ff_amf_write_string(&p, "NetConnection.Connect.Success");
530 ff_amf_write_field_name(&p, "description");
531 ff_amf_write_string(&p, "Connection succeeded.");
532 ff_amf_write_field_name(&p, "objectEncoding");
533 ff_amf_write_number(&p, 0);
534 ff_amf_write_object_end(&p);
536 pkt.size = p - pkt.data;
537 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
538 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
539 ff_rtmp_packet_destroy(&pkt);
543 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
544 RTMP_PT_INVOKE, 0, 30)) < 0)
547 ff_amf_write_string(&p, "onBWDone");
548 ff_amf_write_number(&p, 0);
549 ff_amf_write_null(&p);
550 ff_amf_write_number(&p, 8192);
551 pkt.size = p - pkt.data;
552 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
553 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
554 ff_rtmp_packet_destroy(&pkt);
560 * Generate 'releaseStream' call and send it to the server. It should make
561 * the server release some channel for media streams.
563 static int gen_release_stream(URLContext *s, RTMPContext *rt)
569 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
570 0, 29 + strlen(rt->playpath))) < 0)
573 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
575 ff_amf_write_string(&p, "releaseStream");
576 ff_amf_write_number(&p, ++rt->nb_invokes);
577 ff_amf_write_null(&p);
578 ff_amf_write_string(&p, rt->playpath);
580 return rtmp_send_packet(rt, &pkt, 1);
584 * Generate 'FCPublish' call and send it to the server. It should make
585 * the server preapare for receiving media streams.
587 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
593 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
594 0, 25 + strlen(rt->playpath))) < 0)
597 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
599 ff_amf_write_string(&p, "FCPublish");
600 ff_amf_write_number(&p, ++rt->nb_invokes);
601 ff_amf_write_null(&p);
602 ff_amf_write_string(&p, rt->playpath);
604 return rtmp_send_packet(rt, &pkt, 1);
608 * Generate 'FCUnpublish' call and send it to the server. It should make
609 * the server destroy stream.
611 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
617 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
618 0, 27 + strlen(rt->playpath))) < 0)
621 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
623 ff_amf_write_string(&p, "FCUnpublish");
624 ff_amf_write_number(&p, ++rt->nb_invokes);
625 ff_amf_write_null(&p);
626 ff_amf_write_string(&p, rt->playpath);
628 return rtmp_send_packet(rt, &pkt, 0);
632 * Generate 'createStream' call and send it to the server. It should make
633 * the server allocate some channel for media streams.
635 static int gen_create_stream(URLContext *s, RTMPContext *rt)
641 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
643 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
648 ff_amf_write_string(&p, "createStream");
649 ff_amf_write_number(&p, ++rt->nb_invokes);
650 ff_amf_write_null(&p);
652 return rtmp_send_packet(rt, &pkt, 1);
657 * Generate 'deleteStream' call and send it to the server. It should make
658 * the server remove some channel for media streams.
660 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
666 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
668 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
673 ff_amf_write_string(&p, "deleteStream");
674 ff_amf_write_number(&p, ++rt->nb_invokes);
675 ff_amf_write_null(&p);
676 ff_amf_write_number(&p, rt->stream_id);
678 return rtmp_send_packet(rt, &pkt, 0);
682 * Generate 'getStreamLength' call and send it to the server. If the server
683 * knows the duration of the selected stream, it will reply with the duration
686 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
692 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
693 0, 31 + strlen(rt->playpath))) < 0)
697 ff_amf_write_string(&p, "getStreamLength");
698 ff_amf_write_number(&p, ++rt->nb_invokes);
699 ff_amf_write_null(&p);
700 ff_amf_write_string(&p, rt->playpath);
702 return rtmp_send_packet(rt, &pkt, 1);
706 * Generate client buffer time and send it to the server.
708 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
714 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
719 bytestream_put_be16(&p, 3);
720 bytestream_put_be32(&p, rt->stream_id);
721 bytestream_put_be32(&p, rt->client_buffer_time);
723 return rtmp_send_packet(rt, &pkt, 0);
727 * Generate 'play' call and send it to the server, then ping the server
728 * to start actual playing.
730 static int gen_play(URLContext *s, RTMPContext *rt)
736 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
738 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
739 0, 29 + strlen(rt->playpath))) < 0)
742 pkt.extra = rt->stream_id;
745 ff_amf_write_string(&p, "play");
746 ff_amf_write_number(&p, ++rt->nb_invokes);
747 ff_amf_write_null(&p);
748 ff_amf_write_string(&p, rt->playpath);
749 ff_amf_write_number(&p, rt->live * 1000);
751 return rtmp_send_packet(rt, &pkt, 1);
754 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
760 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
763 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
766 pkt.extra = rt->stream_id;
769 ff_amf_write_string(&p, "seek");
770 ff_amf_write_number(&p, 0); //no tracking back responses
771 ff_amf_write_null(&p); //as usual, the first null param
772 ff_amf_write_number(&p, timestamp); //where we want to jump
774 return rtmp_send_packet(rt, &pkt, 1);
778 * Generate a pause packet that either pauses or unpauses the current stream.
780 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
786 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
789 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
792 pkt.extra = rt->stream_id;
795 ff_amf_write_string(&p, "pause");
796 ff_amf_write_number(&p, 0); //no tracking back responses
797 ff_amf_write_null(&p); //as usual, the first null param
798 ff_amf_write_bool(&p, pause); // pause or unpause
799 ff_amf_write_number(&p, timestamp); //where we pause the stream
801 return rtmp_send_packet(rt, &pkt, 1);
805 * Generate 'publish' call and send it to the server.
807 static int gen_publish(URLContext *s, RTMPContext *rt)
813 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
815 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
816 0, 30 + strlen(rt->playpath))) < 0)
819 pkt.extra = rt->stream_id;
822 ff_amf_write_string(&p, "publish");
823 ff_amf_write_number(&p, ++rt->nb_invokes);
824 ff_amf_write_null(&p);
825 ff_amf_write_string(&p, rt->playpath);
826 ff_amf_write_string(&p, "live");
828 return rtmp_send_packet(rt, &pkt, 1);
832 * Generate ping reply and send it to the server.
834 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
840 if (ppkt->size < 6) {
841 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
843 return AVERROR_INVALIDDATA;
846 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
847 ppkt->timestamp + 1, 6)) < 0)
851 bytestream_put_be16(&p, 7);
852 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
854 return rtmp_send_packet(rt, &pkt, 0);
858 * Generate SWF verification message and send it to the server.
860 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
866 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
867 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
872 bytestream_put_be16(&p, 27);
873 memcpy(p, rt->swfverification, 42);
875 return rtmp_send_packet(rt, &pkt, 0);
879 * Generate server bandwidth message and send it to the server.
881 static int gen_server_bw(URLContext *s, RTMPContext *rt)
887 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
892 bytestream_put_be32(&p, rt->server_bw);
894 return rtmp_send_packet(rt, &pkt, 0);
898 * Generate check bandwidth message and send it to the server.
900 static int gen_check_bw(URLContext *s, RTMPContext *rt)
906 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
911 ff_amf_write_string(&p, "_checkbw");
912 ff_amf_write_number(&p, ++rt->nb_invokes);
913 ff_amf_write_null(&p);
915 return rtmp_send_packet(rt, &pkt, 1);
919 * Generate report on bytes read so far and send it to the server.
921 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
927 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
932 bytestream_put_be32(&p, rt->bytes_read);
934 return rtmp_send_packet(rt, &pkt, 0);
937 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
938 const char *subscribe)
944 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
945 0, 27 + strlen(subscribe))) < 0)
949 ff_amf_write_string(&p, "FCSubscribe");
950 ff_amf_write_number(&p, ++rt->nb_invokes);
951 ff_amf_write_null(&p);
952 ff_amf_write_string(&p, subscribe);
954 return rtmp_send_packet(rt, &pkt, 1);
957 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
958 const uint8_t *key, int keylen, uint8_t *dst)
961 uint8_t hmac_buf[64+32] = {0};
964 sha = av_sha_alloc();
966 return AVERROR(ENOMEM);
969 memcpy(hmac_buf, key, keylen);
971 av_sha_init(sha, 256);
972 av_sha_update(sha,key, keylen);
973 av_sha_final(sha, hmac_buf);
975 for (i = 0; i < 64; i++)
976 hmac_buf[i] ^= HMAC_IPAD_VAL;
978 av_sha_init(sha, 256);
979 av_sha_update(sha, hmac_buf, 64);
981 av_sha_update(sha, src, len);
982 } else { //skip 32 bytes used for storing digest
983 av_sha_update(sha, src, gap);
984 av_sha_update(sha, src + gap + 32, len - gap - 32);
986 av_sha_final(sha, hmac_buf + 64);
988 for (i = 0; i < 64; i++)
989 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
990 av_sha_init(sha, 256);
991 av_sha_update(sha, hmac_buf, 64+32);
992 av_sha_final(sha, dst);
999 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1002 int i, digest_pos = 0;
1004 for (i = 0; i < 4; i++)
1005 digest_pos += buf[i + off];
1006 digest_pos = digest_pos % mod_val + add_val;
1012 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1013 * will be stored) into that packet.
1015 * @param buf handshake data (1536 bytes)
1016 * @param encrypted use an encrypted connection (RTMPE)
1017 * @return offset to the digest inside input data
1019 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1021 int ret, digest_pos;
1024 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1026 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1028 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1029 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1038 * Verify that the received server response has the expected digest value.
1040 * @param buf handshake data received from the server (1536 bytes)
1041 * @param off position to search digest offset from
1042 * @return 0 if digest is valid, digest position otherwise
1044 static int rtmp_validate_digest(uint8_t *buf, int off)
1047 int ret, digest_pos;
1049 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1051 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1052 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1057 if (!memcmp(digest, buf + digest_pos, 32))
1062 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1068 if (rt->swfhash_len != 32) {
1069 av_log(s, AV_LOG_ERROR,
1070 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1071 return AVERROR(EINVAL);
1074 p = &rt->swfverification[0];
1075 bytestream_put_byte(&p, 1);
1076 bytestream_put_byte(&p, 1);
1077 bytestream_put_be32(&p, rt->swfsize);
1078 bytestream_put_be32(&p, rt->swfsize);
1080 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1087 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1088 uint8_t **out_data, int64_t *out_size)
1090 z_stream zs = { 0 };
1095 zs.avail_in = in_size;
1096 zs.next_in = in_data;
1097 ret = inflateInit(&zs);
1099 return AVERROR_UNKNOWN;
1102 uint8_t tmp_buf[16384];
1104 zs.avail_out = sizeof(tmp_buf);
1105 zs.next_out = tmp_buf;
1107 ret = inflate(&zs, Z_NO_FLUSH);
1108 if (ret != Z_OK && ret != Z_STREAM_END) {
1109 ret = AVERROR_UNKNOWN;
1113 size = sizeof(tmp_buf) - zs.avail_out;
1114 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1115 ret = AVERROR(ENOMEM);
1120 memcpy(*out_data + *out_size, tmp_buf, size);
1122 } while (zs.avail_out == 0);
1130 static int rtmp_calc_swfhash(URLContext *s)
1132 RTMPContext *rt = s->priv_data;
1133 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1134 int64_t in_size, out_size;
1140 /* Get the SWF player file. */
1141 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1142 &s->interrupt_callback, NULL)) < 0) {
1143 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1147 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1152 if (!(in_data = av_malloc(in_size))) {
1153 ret = AVERROR(ENOMEM);
1157 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1161 ret = AVERROR_INVALIDDATA;
1165 if (!memcmp(in_data, "CWS", 3)) {
1166 /* Decompress the SWF player file using Zlib. */
1167 if (!(out_data = av_malloc(8))) {
1168 ret = AVERROR(ENOMEM);
1171 *in_data = 'F'; // magic stuff
1172 memcpy(out_data, in_data, 8);
1176 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1177 &out_data, &out_size)) < 0)
1180 av_log(s, AV_LOG_ERROR,
1181 "Zlib is required for decompressing the SWF player file.\n");
1182 ret = AVERROR(EINVAL);
1192 /* Compute the SHA256 hash of the SWF player file. */
1193 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1194 "Genuine Adobe Flash Player 001", 30,
1198 /* Set SWFVerification parameters. */
1199 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1200 rt->swfsize = swfsize;
1204 av_freep(&out_data);
1205 ffurl_close(stream);
1210 * Perform handshake with the server by means of exchanging pseudorandom data
1211 * signed with HMAC-SHA2 digest.
1213 * @return 0 if handshake succeeds, negative value otherwise
1215 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1218 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1219 3, // unencrypted data
1220 0, 0, 0, 0, // client uptime
1226 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1227 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1229 int server_pos, client_pos;
1230 uint8_t digest[32], signature[32];
1233 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1235 av_lfg_init(&rnd, 0xDEADC0DE);
1236 // generate handshake packet - 1536 bytes of pseudorandom data
1237 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1238 tosend[i] = av_lfg_get(&rnd) >> 24;
1240 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1241 /* When the client wants to use RTMPE, we have to change the command
1242 * byte to 0x06 which means to use encrypted data and we have to set
1243 * the flash version to at least 9.0.115.0. */
1250 /* Initialize the Diffie-Hellmann context and generate the public key
1251 * to send to the server. */
1252 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1256 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1260 if ((ret = ffurl_write(rt->stream, tosend,
1261 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1262 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1266 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1267 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1268 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1272 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1273 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1274 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1278 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1279 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1280 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1282 if (rt->is_input && serverdata[5] >= 3) {
1283 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1289 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1294 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1295 return AVERROR(EIO);
1299 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1300 * key are the last 32 bytes of the server handshake. */
1302 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1303 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1307 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1308 rtmp_server_key, sizeof(rtmp_server_key),
1313 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1314 0, digest, 32, signature);
1318 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1319 /* Compute the shared secret key sent by the server and initialize
1320 * the RC4 encryption. */
1321 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1322 tosend + 1, type)) < 0)
1325 /* Encrypt the signature received by the server. */
1326 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1329 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1330 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1331 return AVERROR(EIO);
1334 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1335 tosend[i] = av_lfg_get(&rnd) >> 24;
1336 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1337 rtmp_player_key, sizeof(rtmp_player_key),
1342 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1344 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1348 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1349 /* Encrypt the signature to be send to the server. */
1350 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1351 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1355 // write reply back to the server
1356 if ((ret = ffurl_write(rt->stream, tosend,
1357 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1360 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1361 /* Set RC4 keys for encryption and update the keystreams. */
1362 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1366 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1367 /* Compute the shared secret key sent by the server and initialize
1368 * the RC4 encryption. */
1369 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1370 tosend + 1, 1)) < 0)
1373 if (serverdata[0] == 9) {
1374 /* Encrypt the signature received by the server. */
1375 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1380 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1381 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1384 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1385 /* Set RC4 keys for encryption and update the keystreams. */
1386 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1394 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1395 uint32_t *second_int, char *arraydata,
1400 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1401 RTMP_HANDSHAKE_PACKET_SIZE);
1403 return AVERROR(EIO);
1404 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1405 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1406 " not following standard\n", (int)inoutsize);
1407 return AVERROR(EINVAL);
1410 *first_int = AV_RB32(arraydata);
1411 *second_int = AV_RB32(arraydata + 4);
1415 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1416 uint32_t second_int, char *arraydata, int size)
1420 AV_WB32(arraydata, first_int);
1421 AV_WB32(arraydata + 4, second_int);
1422 inoutsize = ffurl_write(rt->stream, arraydata,
1423 RTMP_HANDSHAKE_PACKET_SIZE);
1424 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1425 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1426 return AVERROR(EIO);
1433 * rtmp handshake server side
1435 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1437 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1439 uint32_t hs_my_epoch;
1440 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1441 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1448 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1449 if (inoutsize <= 0) {
1450 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1451 return AVERROR(EIO);
1454 if (buffer[0] != 3) {
1455 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1456 return AVERROR(EIO);
1458 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1459 av_log(s, AV_LOG_ERROR,
1460 "Unable to write answer - RTMP S0\n");
1461 return AVERROR(EIO);
1464 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1465 RTMP_HANDSHAKE_PACKET_SIZE);
1467 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1471 /* By now same epoch will be sent */
1472 hs_my_epoch = hs_epoch;
1473 /* Generate random */
1474 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1476 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1478 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1479 RTMP_HANDSHAKE_PACKET_SIZE);
1481 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1485 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1486 RTMP_HANDSHAKE_PACKET_SIZE);
1488 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1492 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1493 RTMP_HANDSHAKE_PACKET_SIZE);
1495 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1498 if (temp != hs_my_epoch)
1499 av_log(s, AV_LOG_WARNING,
1500 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1501 if (memcmp(buffer + 8, hs_s1 + 8,
1502 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1503 av_log(s, AV_LOG_WARNING,
1504 "Erroneous C2 Message random does not match up\n");
1509 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1511 RTMPContext *rt = s->priv_data;
1514 if (pkt->size < 4) {
1515 av_log(s, AV_LOG_ERROR,
1516 "Too short chunk size change packet (%d)\n",
1518 return AVERROR_INVALIDDATA;
1521 if (!rt->is_input) {
1522 /* Send the same chunk size change packet back to the server,
1523 * setting the outgoing chunk size to the same as the incoming one. */
1524 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1525 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1527 rt->out_chunk_size = AV_RB32(pkt->data);
1530 rt->in_chunk_size = AV_RB32(pkt->data);
1531 if (rt->in_chunk_size <= 0) {
1532 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1534 return AVERROR_INVALIDDATA;
1536 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1542 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1544 RTMPContext *rt = s->priv_data;
1547 if (pkt->size < 2) {
1548 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1550 return AVERROR_INVALIDDATA;
1553 t = AV_RB16(pkt->data);
1555 if ((ret = gen_pong(s, rt, pkt)) < 0)
1557 } else if (t == 26) {
1559 if ((ret = gen_swf_verification(s, rt)) < 0)
1562 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1569 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1571 RTMPContext *rt = s->priv_data;
1573 if (pkt->size < 4) {
1574 av_log(s, AV_LOG_ERROR,
1575 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1577 return AVERROR_INVALIDDATA;
1580 rt->client_report_size = AV_RB32(pkt->data);
1581 if (rt->client_report_size <= 0) {
1582 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1583 rt->client_report_size);
1584 return AVERROR_INVALIDDATA;
1587 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1588 rt->client_report_size >>= 1;
1593 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1595 RTMPContext *rt = s->priv_data;
1597 if (pkt->size < 4) {
1598 av_log(s, AV_LOG_ERROR,
1599 "Too short server bandwidth report packet (%d)\n",
1601 return AVERROR_INVALIDDATA;
1604 rt->server_bw = AV_RB32(pkt->data);
1605 if (rt->server_bw <= 0) {
1606 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1608 return AVERROR_INVALIDDATA;
1610 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1615 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1616 const char *opaque, const char *challenge)
1619 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1620 struct AVMD5 *md5 = av_md5_alloc();
1622 return AVERROR(ENOMEM);
1624 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1627 av_md5_update(md5, user, strlen(user));
1628 av_md5_update(md5, salt, strlen(salt));
1629 av_md5_update(md5, rt->password, strlen(rt->password));
1630 av_md5_final(md5, hash);
1631 av_base64_encode(hashstr, sizeof(hashstr), hash,
1634 av_md5_update(md5, hashstr, strlen(hashstr));
1636 av_md5_update(md5, opaque, strlen(opaque));
1638 av_md5_update(md5, challenge, strlen(challenge));
1639 av_md5_update(md5, challenge2, strlen(challenge2));
1640 av_md5_final(md5, hash);
1641 av_base64_encode(hashstr, sizeof(hashstr), hash,
1643 snprintf(rt->auth_params, sizeof(rt->auth_params),
1644 "?authmod=%s&user=%s&challenge=%s&response=%s",
1645 "adobe", user, challenge2, hashstr);
1647 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1648 "&opaque=%s", opaque);
1654 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1657 char hashstr1[33], hashstr2[33];
1658 const char *realm = "live";
1659 const char *method = "publish";
1660 const char *qop = "auth";
1661 const char *nc = "00000001";
1663 struct AVMD5 *md5 = av_md5_alloc();
1665 return AVERROR(ENOMEM);
1667 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1670 av_md5_update(md5, user, strlen(user));
1671 av_md5_update(md5, ":", 1);
1672 av_md5_update(md5, realm, strlen(realm));
1673 av_md5_update(md5, ":", 1);
1674 av_md5_update(md5, rt->password, strlen(rt->password));
1675 av_md5_final(md5, hash);
1676 ff_data_to_hex(hashstr1, hash, 16, 1);
1677 hashstr1[32] = '\0';
1680 av_md5_update(md5, method, strlen(method));
1681 av_md5_update(md5, ":/", 2);
1682 av_md5_update(md5, rt->app, strlen(rt->app));
1683 if (!strchr(rt->app, '/'))
1684 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1685 av_md5_final(md5, hash);
1686 ff_data_to_hex(hashstr2, hash, 16, 1);
1687 hashstr2[32] = '\0';
1690 av_md5_update(md5, hashstr1, strlen(hashstr1));
1691 av_md5_update(md5, ":", 1);
1693 av_md5_update(md5, nonce, strlen(nonce));
1694 av_md5_update(md5, ":", 1);
1695 av_md5_update(md5, nc, strlen(nc));
1696 av_md5_update(md5, ":", 1);
1697 av_md5_update(md5, cnonce, strlen(cnonce));
1698 av_md5_update(md5, ":", 1);
1699 av_md5_update(md5, qop, strlen(qop));
1700 av_md5_update(md5, ":", 1);
1701 av_md5_update(md5, hashstr2, strlen(hashstr2));
1702 av_md5_final(md5, hash);
1703 ff_data_to_hex(hashstr1, hash, 16, 1);
1705 snprintf(rt->auth_params, sizeof(rt->auth_params),
1706 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1707 "llnw", user, nonce, cnonce, nc, hashstr1);
1713 static int handle_connect_error(URLContext *s, const char *desc)
1715 RTMPContext *rt = s->priv_data;
1716 char buf[300], *ptr, authmod[15];
1718 const char *user = "", *salt = "", *opaque = NULL,
1719 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1721 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1722 !(cptr = strstr(desc, "authmod=llnw"))) {
1723 av_log(s, AV_LOG_ERROR,
1724 "Unknown connect error (unsupported authentication method?)\n");
1725 return AVERROR_UNKNOWN;
1727 cptr += strlen("authmod=");
1728 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1729 authmod[i++] = *cptr++;
1732 if (!rt->username[0] || !rt->password[0]) {
1733 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1734 return AVERROR_UNKNOWN;
1737 if (strstr(desc, "?reason=authfailed")) {
1738 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1739 return AVERROR_UNKNOWN;
1740 } else if (strstr(desc, "?reason=nosuchuser")) {
1741 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1742 return AVERROR_UNKNOWN;
1745 if (rt->auth_tried) {
1746 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1747 return AVERROR_UNKNOWN;
1750 rt->auth_params[0] = '\0';
1752 if (strstr(desc, "code=403 need auth")) {
1753 snprintf(rt->auth_params, sizeof(rt->auth_params),
1754 "?authmod=%s&user=%s", authmod, rt->username);
1758 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1759 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1760 return AVERROR_UNKNOWN;
1763 av_strlcpy(buf, cptr + 1, sizeof(buf));
1767 char *next = strchr(ptr, '&');
1768 char *value = strchr(ptr, '=');
1773 if (!strcmp(ptr, "user")) {
1775 } else if (!strcmp(ptr, "salt")) {
1777 } else if (!strcmp(ptr, "opaque")) {
1779 } else if (!strcmp(ptr, "challenge")) {
1781 } else if (!strcmp(ptr, "nonce")) {
1784 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1787 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1792 if (!strcmp(authmod, "adobe")) {
1793 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1796 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1804 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1806 RTMPContext *rt = s->priv_data;
1807 const uint8_t *data_end = pkt->data + pkt->size;
1808 char *tracked_method = NULL;
1809 int level = AV_LOG_ERROR;
1810 uint8_t tmpstr[256];
1813 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1816 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1817 "description", tmpstr, sizeof(tmpstr))) {
1818 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1819 !strcmp(tracked_method, "releaseStream") ||
1820 !strcmp(tracked_method, "FCSubscribe") ||
1821 !strcmp(tracked_method, "FCPublish"))) {
1822 /* Gracefully ignore Adobe-specific historical artifact errors. */
1823 level = AV_LOG_WARNING;
1825 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1826 ret = handle_connect_error(s, tmpstr);
1828 rt->do_reconnect = 1;
1829 level = AV_LOG_VERBOSE;
1832 ret = AVERROR_UNKNOWN;
1833 av_log(s, level, "Server error: %s\n", tmpstr);
1836 av_free(tracked_method);
1840 static int write_begin(URLContext *s)
1842 RTMPContext *rt = s->priv_data;
1844 RTMPPacket spkt = { 0 };
1847 // Send Stream Begin 1
1848 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1849 RTMP_PT_PING, 0, 6)) < 0) {
1850 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1854 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1855 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1856 bytestream2_put_be32(&pbc, rt->nb_streamid);
1858 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1859 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1861 ff_rtmp_packet_destroy(&spkt);
1866 static int write_status(URLContext *s, RTMPPacket *pkt,
1867 const char *status, const char *filename)
1869 RTMPContext *rt = s->priv_data;
1870 RTMPPacket spkt = { 0 };
1871 char statusmsg[128];
1875 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1877 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1878 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1883 spkt.extra = pkt->extra;
1884 ff_amf_write_string(&pp, "onStatus");
1885 ff_amf_write_number(&pp, 0);
1886 ff_amf_write_null(&pp);
1888 ff_amf_write_object_start(&pp);
1889 ff_amf_write_field_name(&pp, "level");
1890 ff_amf_write_string(&pp, "status");
1891 ff_amf_write_field_name(&pp, "code");
1892 ff_amf_write_string(&pp, status);
1893 ff_amf_write_field_name(&pp, "description");
1894 snprintf(statusmsg, sizeof(statusmsg),
1895 "%s is now published", filename);
1896 ff_amf_write_string(&pp, statusmsg);
1897 ff_amf_write_field_name(&pp, "details");
1898 ff_amf_write_string(&pp, filename);
1899 ff_amf_write_field_name(&pp, "clientid");
1900 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1901 ff_amf_write_string(&pp, statusmsg);
1902 ff_amf_write_object_end(&pp);
1904 spkt.size = pp - spkt.data;
1905 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1906 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1907 ff_rtmp_packet_destroy(&spkt);
1912 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1914 RTMPContext *rt = s->priv_data;
1920 const uint8_t *p = pkt->data;
1922 RTMPPacket spkt = { 0 };
1926 bytestream2_init(&gbc, p, pkt->size);
1927 if (ff_amf_read_string(&gbc, command, sizeof(command),
1929 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1930 return AVERROR_INVALIDDATA;
1933 ret = ff_amf_read_number(&gbc, &seqnum);
1936 ret = ff_amf_read_null(&gbc);
1939 if (!strcmp(command, "FCPublish") ||
1940 !strcmp(command, "publish")) {
1941 ret = ff_amf_read_string(&gbc, filename,
1942 sizeof(filename), &stringlen);
1945 pchar = strrchr(s->filename, '/');
1947 av_log(s, AV_LOG_WARNING,
1948 "Unable to find / in url %s, bad format\n",
1950 pchar = s->filename;
1953 if (strcmp(pchar, filename))
1954 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1955 " %s\n", filename, pchar);
1957 rt->state = STATE_RECEIVING;
1960 if (!strcmp(command, "FCPublish")) {
1961 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1963 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1964 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1968 ff_amf_write_string(&pp, "onFCPublish");
1969 } else if (!strcmp(command, "publish")) {
1970 ret = write_begin(s);
1974 // Send onStatus(NetStream.Publish.Start)
1975 return write_status(s, pkt, "NetStream.Publish.Start",
1977 } else if (!strcmp(command, "play")) {
1978 ret = write_begin(s);
1981 rt->state = STATE_SENDING;
1982 return write_status(s, pkt, "NetStream.Play.Start",
1985 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1987 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1988 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1992 ff_amf_write_string(&pp, "_result");
1993 ff_amf_write_number(&pp, seqnum);
1994 ff_amf_write_null(&pp);
1995 if (!strcmp(command, "createStream")) {
1997 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1998 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1999 ff_amf_write_number(&pp, rt->nb_streamid);
2000 /* By now we don't control which streams are removed in
2001 * deleteStream. There is no stream creation control
2002 * if a client creates more than 2^32 - 2 streams. */
2005 spkt.size = pp - spkt.data;
2006 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2007 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2008 ff_rtmp_packet_destroy(&spkt);
2013 * Read the AMF_NUMBER response ("_result") to a function call
2014 * (e.g. createStream()). This response should be made up of the AMF_STRING
2015 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2016 * successful response, we will return set the value to number (otherwise number
2017 * will not be changed).
2019 * @return 0 if reading the value succeeds, negative value otherwiss
2021 static int read_number_result(RTMPPacket *pkt, double *number)
2023 // We only need to fit "_result" in this.
2024 uint8_t strbuffer[8];
2029 bytestream2_init(&gbc, pkt->data, pkt->size);
2031 // Value 1/4: "_result" as AMF_STRING
2032 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2033 return AVERROR_INVALIDDATA;
2034 if (strcmp(strbuffer, "_result"))
2035 return AVERROR_INVALIDDATA;
2036 // Value 2/4: The callee reference number
2037 if (ff_amf_read_number(&gbc, &numbuffer))
2038 return AVERROR_INVALIDDATA;
2040 if (ff_amf_read_null(&gbc))
2041 return AVERROR_INVALIDDATA;
2042 // Value 4/4: The resonse as AMF_NUMBER
2043 if (ff_amf_read_number(&gbc, &numbuffer))
2044 return AVERROR_INVALIDDATA;
2046 *number = numbuffer;
2051 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2053 RTMPContext *rt = s->priv_data;
2054 char *tracked_method = NULL;
2057 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2060 if (!tracked_method) {
2061 /* Ignore this reply when the current method is not tracked. */
2065 if (!strcmp(tracked_method, "connect")) {
2066 if (!rt->is_input) {
2067 if ((ret = gen_release_stream(s, rt)) < 0)
2070 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2073 if ((ret = gen_server_bw(s, rt)) < 0)
2077 if ((ret = gen_create_stream(s, rt)) < 0)
2081 /* Send the FCSubscribe command when the name of live
2082 * stream is defined by the user or if it's a live stream. */
2083 if (rt->subscribe) {
2084 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2086 } else if (rt->live == -1) {
2087 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2091 } else if (!strcmp(tracked_method, "createStream")) {
2093 if (read_number_result(pkt, &stream_id)) {
2094 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2096 rt->stream_id = stream_id;
2099 if (!rt->is_input) {
2100 if ((ret = gen_publish(s, rt)) < 0)
2103 if (rt->live != -1) {
2104 if ((ret = gen_get_stream_length(s, rt)) < 0)
2107 if ((ret = gen_play(s, rt)) < 0)
2109 if ((ret = gen_buffer_time(s, rt)) < 0)
2112 } else if (!strcmp(tracked_method, "getStreamLength")) {
2113 if (read_number_result(pkt, &rt->duration)) {
2114 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2119 av_free(tracked_method);
2123 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2125 RTMPContext *rt = s->priv_data;
2126 const uint8_t *data_end = pkt->data + pkt->size;
2127 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2128 uint8_t tmpstr[256];
2131 for (i = 0; i < 2; i++) {
2132 t = ff_amf_tag_size(ptr, data_end);
2138 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2139 if (!t && !strcmp(tmpstr, "error")) {
2140 t = ff_amf_get_field_value(ptr, data_end,
2141 "description", tmpstr, sizeof(tmpstr));
2142 if (t || !tmpstr[0])
2143 t = ff_amf_get_field_value(ptr, data_end, "code",
2144 tmpstr, sizeof(tmpstr));
2146 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2150 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2151 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2152 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2153 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2154 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2155 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2160 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2162 RTMPContext *rt = s->priv_data;
2165 //TODO: check for the messages sent for wrong state?
2166 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2167 if ((ret = handle_invoke_error(s, pkt)) < 0)
2169 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2170 if ((ret = handle_invoke_result(s, pkt)) < 0)
2172 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2173 if ((ret = handle_invoke_status(s, pkt)) < 0)
2175 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2176 if ((ret = gen_check_bw(s, rt)) < 0)
2178 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2179 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2180 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2181 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2182 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2183 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2184 if ((ret = send_invoke_response(s, pkt)) < 0)
2191 static int update_offset(RTMPContext *rt, int size)
2195 // generate packet header and put data into buffer for FLV demuxer
2196 if (rt->flv_off < rt->flv_size) {
2197 // There is old unread data in the buffer, thus append at the end
2198 old_flv_size = rt->flv_size;
2199 rt->flv_size += size;
2201 // All data has been read, write the new data at the start of the buffer
2203 rt->flv_size = size;
2207 return old_flv_size;
2210 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2212 int old_flv_size, ret;
2214 const uint8_t *data = pkt->data + skip;
2215 const int size = pkt->size - skip;
2216 uint32_t ts = pkt->timestamp;
2218 if (pkt->type == RTMP_PT_AUDIO) {
2220 } else if (pkt->type == RTMP_PT_VIDEO) {
2224 old_flv_size = update_offset(rt, size + 15);
2226 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2227 rt->flv_size = rt->flv_off = 0;
2230 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2231 bytestream2_skip_p(&pbc, old_flv_size);
2232 bytestream2_put_byte(&pbc, pkt->type);
2233 bytestream2_put_be24(&pbc, size);
2234 bytestream2_put_be24(&pbc, ts);
2235 bytestream2_put_byte(&pbc, ts >> 24);
2236 bytestream2_put_be24(&pbc, 0);
2237 bytestream2_put_buffer(&pbc, data, size);
2238 bytestream2_put_be32(&pbc, 0);
2243 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2245 RTMPContext *rt = s->priv_data;
2246 uint8_t commandbuffer[64];
2247 char statusmsg[128];
2248 int stringlen, ret, skip = 0;
2251 bytestream2_init(&gbc, pkt->data, pkt->size);
2252 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2254 return AVERROR_INVALIDDATA;
2256 if (!strcmp(commandbuffer, "onMetaData")) {
2257 // metadata properties should be stored in a mixed array
2258 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2259 // We have found a metaData Array so flv can determine the streams
2261 rt->received_metadata = 1;
2262 // skip 32-bit max array index
2263 bytestream2_skip(&gbc, 4);
2264 while (bytestream2_get_bytes_left(&gbc) > 3) {
2265 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2267 return AVERROR_INVALIDDATA;
2268 // We do not care about the content of the property (yet).
2269 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2271 return AVERROR_INVALIDDATA;
2272 bytestream2_skip(&gbc, stringlen);
2274 // The presence of the following properties indicates that the
2275 // respective streams are present.
2276 if (!strcmp(statusmsg, "videocodecid")) {
2279 if (!strcmp(statusmsg, "audiocodecid")) {
2283 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2284 return AVERROR_INVALIDDATA;
2288 // Skip the @setDataFrame string and validate it is a notification
2289 if (!strcmp(commandbuffer, "@setDataFrame")) {
2290 skip = gbc.buffer - pkt->data;
2291 ret = ff_amf_read_string(&gbc, statusmsg,
2292 sizeof(statusmsg), &stringlen);
2294 return AVERROR_INVALIDDATA;
2297 return append_flv_data(rt, pkt, skip);
2301 * Parse received packet and possibly perform some action depending on
2302 * the packet contents.
2303 * @return 0 for no errors, negative values for serious errors which prevent
2304 * further communications, positive values for uncritical errors
2306 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2311 ff_rtmp_packet_dump(s, pkt);
2314 switch (pkt->type) {
2315 case RTMP_PT_BYTES_READ:
2316 av_dlog(s, "received bytes read report\n");
2318 case RTMP_PT_CHUNK_SIZE:
2319 if ((ret = handle_chunk_size(s, pkt)) < 0)
2323 if ((ret = handle_ping(s, pkt)) < 0)
2326 case RTMP_PT_CLIENT_BW:
2327 if ((ret = handle_client_bw(s, pkt)) < 0)
2330 case RTMP_PT_SERVER_BW:
2331 if ((ret = handle_server_bw(s, pkt)) < 0)
2334 case RTMP_PT_INVOKE:
2335 if ((ret = handle_invoke(s, pkt)) < 0)
2340 case RTMP_PT_METADATA:
2341 case RTMP_PT_NOTIFY:
2342 /* Audio, Video and Metadata packets are parsed in get_packet() */
2345 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2351 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2353 int ret, old_flv_size, type;
2354 const uint8_t *next;
2357 uint32_t ts, cts, pts = 0;
2359 old_flv_size = update_offset(rt, pkt->size);
2361 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2362 rt->flv_size = rt->flv_off = 0;
2367 p = rt->flv_data + old_flv_size;
2369 /* copy data while rewriting timestamps */
2370 ts = pkt->timestamp;
2372 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2373 type = bytestream_get_byte(&next);
2374 size = bytestream_get_be24(&next);
2375 cts = bytestream_get_be24(&next);
2376 cts |= bytestream_get_byte(&next) << 24;
2381 if (size + 3 + 4 > pkt->data + pkt->size - next)
2383 bytestream_put_byte(&p, type);
2384 bytestream_put_be24(&p, size);
2385 bytestream_put_be24(&p, ts);
2386 bytestream_put_byte(&p, ts >> 24);
2387 memcpy(p, next, size + 3 + 4);
2388 next += size + 3 + 4;
2391 if (p != rt->flv_data + rt->flv_size) {
2392 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2393 "RTMP_PT_METADATA packet\n");
2394 rt->flv_size = p - rt->flv_data;
2401 * Interact with the server by receiving and sending RTMP packets until
2402 * there is some significant data (media data or expected status notification).
2404 * @param s reading context
2405 * @param for_header non-zero value tells function to work until it
2406 * gets notification from the server that playing has been started,
2407 * otherwise function will work until some media data is received (or
2409 * @return 0 for successful operation, negative value in case of error
2411 static int get_packet(URLContext *s, int for_header)
2413 RTMPContext *rt = s->priv_data;
2416 if (rt->state == STATE_STOPPED)
2420 RTMPPacket rpkt = { 0 };
2421 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2422 rt->in_chunk_size, &rt->prev_pkt[0],
2423 &rt->nb_prev_pkt[0])) <= 0) {
2425 return AVERROR(EAGAIN);
2427 return AVERROR(EIO);
2431 // Track timestamp for later use
2432 rt->last_timestamp = rpkt.timestamp;
2434 rt->bytes_read += ret;
2435 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2436 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2437 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2439 rt->last_bytes_read = rt->bytes_read;
2442 ret = rtmp_parse_result(s, rt, &rpkt);
2444 // At this point we must check if we are in the seek state and continue
2445 // with the next packet. handle_invoke will get us out of this state
2446 // when the right message is encountered
2447 if (rt->state == STATE_SEEKING) {
2448 ff_rtmp_packet_destroy(&rpkt);
2449 // We continue, let the natural flow of things happen:
2450 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2454 if (ret < 0) {//serious error in current packet
2455 ff_rtmp_packet_destroy(&rpkt);
2458 if (rt->do_reconnect && for_header) {
2459 ff_rtmp_packet_destroy(&rpkt);
2462 if (rt->state == STATE_STOPPED) {
2463 ff_rtmp_packet_destroy(&rpkt);
2466 if (for_header && (rt->state == STATE_PLAYING ||
2467 rt->state == STATE_PUBLISHING ||
2468 rt->state == STATE_SENDING ||
2469 rt->state == STATE_RECEIVING)) {
2470 ff_rtmp_packet_destroy(&rpkt);
2473 if (!rpkt.size || !rt->is_input) {
2474 ff_rtmp_packet_destroy(&rpkt);
2477 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2478 ret = append_flv_data(rt, &rpkt, 0);
2479 ff_rtmp_packet_destroy(&rpkt);
2481 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2482 ret = handle_notify(s, &rpkt);
2483 ff_rtmp_packet_destroy(&rpkt);
2485 } else if (rpkt.type == RTMP_PT_METADATA) {
2486 ret = handle_metadata(rt, &rpkt);
2487 ff_rtmp_packet_destroy(&rpkt);
2490 ff_rtmp_packet_destroy(&rpkt);
2494 static int rtmp_close(URLContext *h)
2496 RTMPContext *rt = h->priv_data;
2499 if (!rt->is_input) {
2500 rt->flv_data = NULL;
2501 if (rt->out_pkt.size)
2502 ff_rtmp_packet_destroy(&rt->out_pkt);
2503 if (rt->state > STATE_FCPUBLISH)
2504 ret = gen_fcunpublish_stream(h, rt);
2506 if (rt->state > STATE_HANDSHAKED)
2507 ret = gen_delete_stream(h, rt);
2508 for (i = 0; i < 2; i++) {
2509 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2510 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2511 av_freep(&rt->prev_pkt[i]);
2514 free_tracked_methods(rt);
2515 av_freep(&rt->flv_data);
2516 ffurl_close(rt->stream);
2521 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2522 * demuxer about the duration of the stream.
2524 * This should only be done if there was no real onMetadata packet sent by the
2525 * server at the start of the stream and if we were able to retrieve a valid
2526 * duration via a getStreamLength call.
2528 * @return 0 for successful operation, negative value in case of error
2530 static int inject_fake_duration_metadata(RTMPContext *rt)
2532 // We need to insert the metdata packet directly after the FLV
2533 // header, i.e. we need to move all other already read data by the
2534 // size of our fake metadata packet.
2537 // Keep old flv_data pointer
2538 uint8_t* old_flv_data = rt->flv_data;
2539 // Allocate a new flv_data pointer with enough space for the additional package
2540 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2541 rt->flv_data = old_flv_data;
2542 return AVERROR(ENOMEM);
2546 memcpy(rt->flv_data, old_flv_data, 13);
2547 // Copy remaining packets
2548 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2549 // Increase the size by the injected packet
2551 // Delete the old FLV data
2552 av_free(old_flv_data);
2554 p = rt->flv_data + 13;
2555 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2556 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2557 bytestream_put_be24(&p, 0); // timestamp
2558 bytestream_put_be32(&p, 0); // reserved
2560 // first event name as a string
2561 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2562 // "onMetaData" as AMF string
2563 bytestream_put_be16(&p, 10);
2564 bytestream_put_buffer(&p, "onMetaData", 10);
2566 // mixed array (hash) with size and string/type/data tuples
2567 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2568 bytestream_put_be32(&p, 1); // metadata_count
2570 // "duration" as AMF string
2571 bytestream_put_be16(&p, 8);
2572 bytestream_put_buffer(&p, "duration", 8);
2573 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2574 bytestream_put_be64(&p, av_double2int(rt->duration));
2577 bytestream_put_be16(&p, 0); // Empty string
2578 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2579 bytestream_put_be32(&p, 40); // size of data part (sum of all parts below)
2585 * Open RTMP connection and verify that the stream can be played.
2587 * URL syntax: rtmp://server[:port][/app][/playpath]
2588 * where 'app' is first one or two directories in the path
2589 * (e.g. /ondemand/, /flash/live/, etc.)
2590 * and 'playpath' is a file name (the rest of the path,
2591 * may be prefixed with "mp4:")
2593 static int rtmp_open(URLContext *s, const char *uri, int flags)
2595 RTMPContext *rt = s->priv_data;
2596 char proto[8], hostname[256], path[1024], auth[100], *fname;
2597 char *old_app, *qmark, *n, fname_buffer[1024];
2600 AVDictionary *opts = NULL;
2603 if (rt->listen_timeout > 0)
2606 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2608 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2609 hostname, sizeof(hostname), &port,
2610 path, sizeof(path), s->filename);
2612 n = strchr(path, ' ');
2614 av_log(s, AV_LOG_WARNING,
2615 "Detected librtmp style URL parameters, these aren't supported "
2616 "by the libavformat internal RTMP handler currently enabled. "
2617 "See the documentation for the correct way to pass parameters.\n");
2618 *n = '\0'; // Trim not supported part
2622 char *ptr = strchr(auth, ':');
2625 av_strlcpy(rt->username, auth, sizeof(rt->username));
2626 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2630 if (rt->listen && strcmp(proto, "rtmp")) {
2631 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2633 return AVERROR(EINVAL);
2635 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2636 if (!strcmp(proto, "rtmpts"))
2637 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2639 /* open the http tunneling connection */
2640 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2641 } else if (!strcmp(proto, "rtmps")) {
2642 /* open the tls connection */
2644 port = RTMPS_DEFAULT_PORT;
2645 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2646 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2647 if (!strcmp(proto, "rtmpte"))
2648 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2650 /* open the encrypted connection */
2651 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2654 /* open the tcp connection */
2656 port = RTMP_DEFAULT_PORT;
2658 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2659 "?listen&listen_timeout=%d",
2660 rt->listen_timeout * 1000);
2662 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2666 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2667 &s->interrupt_callback, &opts)) < 0) {
2668 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2672 if (rt->swfverify) {
2673 if ((ret = rtmp_calc_swfhash(s)) < 0)
2677 rt->state = STATE_START;
2678 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2680 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2683 rt->out_chunk_size = 128;
2684 rt->in_chunk_size = 128; // Probably overwritten later
2685 rt->state = STATE_HANDSHAKED;
2687 // Keep the application name when it has been defined by the user.
2690 rt->app = av_malloc(APP_MAX_LENGTH);
2692 ret = AVERROR(ENOMEM);
2696 //extract "app" part from path
2697 qmark = strchr(path, '?');
2698 if (qmark && strstr(qmark, "slist=")) {
2700 // After slist we have the playpath, before the params, the app
2701 av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH));
2702 fname = strstr(path, "slist=") + 6;
2703 // Strip any further query parameters from fname
2704 amp = strchr(fname, '&');
2706 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2707 sizeof(fname_buffer)));
2708 fname = fname_buffer;
2710 } else if (!strncmp(path, "/ondemand/", 10)) {
2712 memcpy(rt->app, "ondemand", 9);
2714 char *next = *path ? path + 1 : path;
2715 char *p = strchr(next, '/');
2718 // If name of application has been defined by the user, assume that
2719 // playpath is provided in the URL
2723 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2726 // make sure we do not mismatch a playpath for an application instance
2727 char *c = strchr(p + 1, ':');
2728 fname = strchr(p + 1, '/');
2729 if (!fname || (c && c < fname)) {
2731 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2734 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2740 // The name of application has been defined by the user, override it.
2741 if (strlen(old_app) >= APP_MAX_LENGTH) {
2742 ret = AVERROR(EINVAL);
2749 if (!rt->playpath) {
2750 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2751 if (!rt->playpath) {
2752 ret = AVERROR(ENOMEM);
2757 int len = strlen(fname);
2758 if (!strchr(fname, ':') && len >= 4 &&
2759 (!strcmp(fname + len - 4, ".f4v") ||
2760 !strcmp(fname + len - 4, ".mp4"))) {
2761 memcpy(rt->playpath, "mp4:", 5);
2763 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2764 fname[len - 4] = '\0';
2765 rt->playpath[0] = 0;
2767 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2769 rt->playpath[0] = '\0';
2774 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2776 ret = AVERROR(ENOMEM);
2779 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2780 port, "/%s", rt->app);
2783 if (!rt->flashver) {
2784 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2785 if (!rt->flashver) {
2786 ret = AVERROR(ENOMEM);
2790 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2791 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2792 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2794 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2795 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2799 rt->client_report_size = 1048576;
2803 rt->received_metadata = 0;
2804 rt->last_bytes_read = 0;
2805 rt->server_bw = 2500000;
2808 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2809 proto, path, rt->app, rt->playpath);
2811 if ((ret = gen_connect(s, rt)) < 0)
2814 if ((ret = read_connect(s, s->priv_data)) < 0)
2819 ret = get_packet(s, 1);
2820 } while (ret == AVERROR(EAGAIN));
2824 if (rt->do_reconnect) {
2826 ffurl_close(rt->stream);
2828 rt->do_reconnect = 0;
2830 for (i = 0; i < 2; i++)
2831 memset(rt->prev_pkt[i], 0,
2832 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2833 free_tracked_methods(rt);
2838 // generate FLV header for demuxer
2840 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2843 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2845 // Read packets until we reach the first A/V packet or read metadata.
2846 // If there was a metadata package in front of the A/V packets, we can
2847 // build the FLV header from this. If we do not receive any metadata,
2848 // the FLV decoder will allocate the needed streams when their first
2849 // audio or video packet arrives.
2850 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2851 if ((ret = get_packet(s, 0)) < 0)
2855 // Either after we have read the metadata or (if there is none) the
2856 // first packet of an A/V stream, we have a better knowledge about the
2857 // streams, so set the FLV header accordingly.
2858 if (rt->has_audio) {
2859 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2861 if (rt->has_video) {
2862 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2865 // If we received the first packet of an A/V stream and no metadata but
2866 // the server returned a valid duration, create a fake metadata packet
2867 // to inform the FLV decoder about the duration.
2868 if (!rt->received_metadata && rt->duration > 0) {
2869 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2874 rt->flv_data = NULL;
2876 rt->skip_bytes = 13;
2879 s->max_packet_size = rt->stream->max_packet_size;
2884 av_dict_free(&opts);
2889 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2891 RTMPContext *rt = s->priv_data;
2892 int orig_size = size;
2896 int data_left = rt->flv_size - rt->flv_off;
2898 if (data_left >= size) {
2899 memcpy(buf, rt->flv_data + rt->flv_off, size);
2900 rt->flv_off += size;
2903 if (data_left > 0) {
2904 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2907 rt->flv_off = rt->flv_size;
2910 if ((ret = get_packet(s, 0)) < 0)
2916 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2919 RTMPContext *rt = s->priv_data;
2921 av_log(s, AV_LOG_DEBUG,
2922 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2923 stream_index, timestamp, flags);
2924 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2925 av_log(s, AV_LOG_ERROR,
2926 "Unable to send seek command on stream index %d at timestamp "
2927 "%"PRId64" with flags %08x\n",
2928 stream_index, timestamp, flags);
2931 rt->flv_off = rt->flv_size;
2932 rt->state = STATE_SEEKING;
2936 static int rtmp_pause(URLContext *s, int pause)
2938 RTMPContext *rt = s->priv_data;
2940 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2941 rt->last_timestamp);
2942 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2943 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2944 rt->last_timestamp);
2950 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2952 RTMPContext *rt = s->priv_data;
2953 int size_temp = size;
2954 int pktsize, pkttype;
2956 const uint8_t *buf_temp = buf;
2961 if (rt->skip_bytes) {
2962 int skip = FFMIN(rt->skip_bytes, size_temp);
2965 rt->skip_bytes -= skip;
2969 if (rt->flv_header_bytes < RTMP_HEADER) {
2970 const uint8_t *header = rt->flv_header;
2971 int copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2972 int channel = RTMP_AUDIO_CHANNEL;
2973 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2974 rt->flv_header_bytes += copy;
2976 if (rt->flv_header_bytes < RTMP_HEADER)
2979 pkttype = bytestream_get_byte(&header);
2980 pktsize = bytestream_get_be24(&header);
2981 ts = bytestream_get_be24(&header);
2982 ts |= bytestream_get_byte(&header) << 24;
2983 bytestream_get_be24(&header);
2984 rt->flv_size = pktsize;
2986 if (pkttype == RTMP_PT_VIDEO)
2987 channel = RTMP_VIDEO_CHANNEL;
2989 //force 12bytes header
2990 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2991 pkttype == RTMP_PT_NOTIFY) {
2992 if (pkttype == RTMP_PT_NOTIFY)
2994 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2995 &rt->nb_prev_pkt[1],
2998 rt->prev_pkt[1][channel].channel_id = 0;
3001 //this can be a big packet, it's better to send it right here
3002 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3003 pkttype, ts, pktsize)) < 0)
3006 rt->out_pkt.extra = rt->stream_id;
3007 rt->flv_data = rt->out_pkt.data;
3009 if (pkttype == RTMP_PT_NOTIFY)
3010 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
3013 if (rt->flv_size - rt->flv_off > size_temp) {
3014 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
3015 rt->flv_off += size_temp;
3018 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
3019 size_temp -= rt->flv_size - rt->flv_off;
3020 rt->flv_off += rt->flv_size - rt->flv_off;
3023 if (rt->flv_off == rt->flv_size) {
3026 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3030 rt->flv_header_bytes = 0;
3031 rt->flv_nb_packets++;
3033 } while (buf_temp - buf < size);
3035 if (rt->flv_nb_packets < rt->flush_interval)
3037 rt->flv_nb_packets = 0;
3039 /* set stream into nonblocking mode */
3040 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3042 /* try to read one byte from the stream */
3043 ret = ffurl_read(rt->stream, &c, 1);
3045 /* switch the stream back into blocking mode */
3046 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3048 if (ret == AVERROR(EAGAIN)) {
3049 /* no incoming data to handle */
3051 } else if (ret < 0) {
3053 } else if (ret == 1) {
3054 RTMPPacket rpkt = { 0 };
3056 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3059 &rt->nb_prev_pkt[0], c)) <= 0)
3062 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3065 ff_rtmp_packet_destroy(&rpkt);
3071 #define OFFSET(x) offsetof(RTMPContext, x)
3072 #define DEC AV_OPT_FLAG_DECODING_PARAM
3073 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3075 static const AVOption rtmp_options[] = {
3076 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3077 {"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},
3078 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3079 {"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},
3080 {"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},
3081 {"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"},
3082 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3083 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3084 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3085 {"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},
3086 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3087 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3088 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3089 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3090 {"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},
3091 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3092 {"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},
3093 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3094 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3095 {"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" },
3099 #define RTMP_PROTOCOL(flavor) \
3100 static const AVClass flavor##_class = { \
3101 .class_name = #flavor, \
3102 .item_name = av_default_item_name, \
3103 .option = rtmp_options, \
3104 .version = LIBAVUTIL_VERSION_INT, \
3107 URLProtocol ff_##flavor##_protocol = { \
3109 .url_open = rtmp_open, \
3110 .url_read = rtmp_read, \
3111 .url_read_seek = rtmp_seek, \
3112 .url_read_pause = rtmp_pause, \
3113 .url_write = rtmp_write, \
3114 .url_close = rtmp_close, \
3115 .priv_data_size = sizeof(RTMPContext), \
3116 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3117 .priv_data_class= &flavor##_class, \
3122 RTMP_PROTOCOL(rtmpe)
3123 RTMP_PROTOCOL(rtmps)
3124 RTMP_PROTOCOL(rtmpt)
3125 RTMP_PROTOCOL(rtmpte)
3126 RTMP_PROTOCOL(rtmpts)