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 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
100 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
101 int flv_header_bytes; ///< number of initialized bytes in flv_header
102 int nb_invokes; ///< keeps track of invoke messages
103 char* tcurl; ///< url of the target stream
104 char* flashver; ///< version of the flash plugin
105 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
106 int swfhash_len; ///< length of the SHA256 hash
107 int swfsize; ///< size of the decompressed SWF file
108 char* swfurl; ///< url of the swf player
109 char* swfverify; ///< URL to player swf file, compute hash/size automatically
110 char swfverification[42]; ///< hash of the SWF verification
111 char* pageurl; ///< url of the web page
112 char* subscribe; ///< name of live stream to subscribe
113 int server_bw; ///< server bandwidth
114 int client_buffer_time; ///< client buffer time in ms
115 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
116 int encrypted; ///< use an encrypted connection (RTMPE only)
117 TrackedMethod*tracked_methods; ///< tracked methods buffer
118 int nb_tracked_methods; ///< number of tracked methods
119 int tracked_methods_size; ///< size of the tracked methods buffer
120 int listen; ///< listen mode flag
121 int listen_timeout; ///< listen timeout to wait for new connections
122 int nb_streamid; ///< The next stream id to return on createStream calls
125 char auth_params[500];
130 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
131 /** Client key used for digest signing */
132 static const uint8_t rtmp_player_key[] = {
133 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
134 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
136 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
137 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
138 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
141 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
142 /** Key used for RTMP server digest signing */
143 static const uint8_t rtmp_server_key[] = {
144 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
145 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
146 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
148 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
149 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
150 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
153 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
155 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
159 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
160 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
161 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
162 sizeof(*rt->tracked_methods))) < 0) {
163 rt->nb_tracked_methods = 0;
164 rt->tracked_methods_size = 0;
169 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
170 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
171 return AVERROR(ENOMEM);
172 rt->tracked_methods[rt->nb_tracked_methods].id = id;
173 rt->nb_tracked_methods++;
178 static void del_tracked_method(RTMPContext *rt, int index)
180 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
181 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
182 rt->nb_tracked_methods--;
185 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
186 char **tracked_method)
188 RTMPContext *rt = s->priv_data;
194 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
195 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
198 for (i = 0; i < rt->nb_tracked_methods; i++) {
199 if (rt->tracked_methods[i].id != pkt_id)
202 *tracked_method = rt->tracked_methods[i].name;
203 del_tracked_method(rt, i);
210 static void free_tracked_methods(RTMPContext *rt)
214 for (i = 0; i < rt->nb_tracked_methods; i ++)
215 av_free(rt->tracked_methods[i].name);
216 av_free(rt->tracked_methods);
217 rt->tracked_methods = NULL;
218 rt->tracked_methods_size = 0;
219 rt->nb_tracked_methods = 0;
222 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
226 if (pkt->type == RTMP_PT_INVOKE && track) {
232 bytestream2_init(&gbc, pkt->data, pkt->size);
233 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
236 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
239 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
243 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
244 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
246 ff_rtmp_packet_destroy(pkt);
250 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
255 /* The type must be B for Boolean, N for number, S for string, O for
256 * object, or Z for null. For Booleans the data must be either 0 or 1 for
257 * FALSE or TRUE, respectively. Likewise for Objects the data must be
258 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
259 * may be named, by prefixing the type with 'N' and specifying the name
260 * before the value (ie. NB:myFlag:1). This option may be used multiple times
261 * to construct arbitrary AMF sequences. */
262 if (param[0] && param[1] == ':') {
265 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
268 value = strchr(field, ':');
274 ff_amf_write_field_name(p, field);
281 ff_amf_write_bool(p, value[0] != '0');
284 ff_amf_write_string(p, value);
287 ff_amf_write_number(p, strtod(value, NULL));
290 ff_amf_write_null(p);
294 ff_amf_write_object_start(p);
296 ff_amf_write_object_end(p);
306 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
307 return AVERROR(EINVAL);
311 * Generate 'connect' call and send it to the server.
313 static int gen_connect(URLContext *s, RTMPContext *rt)
319 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
320 0, 4096 + APP_MAX_LENGTH)) < 0)
325 ff_amf_write_string(&p, "connect");
326 ff_amf_write_number(&p, ++rt->nb_invokes);
327 ff_amf_write_object_start(&p);
328 ff_amf_write_field_name(&p, "app");
329 ff_amf_write_string2(&p, rt->app, rt->auth_params);
332 ff_amf_write_field_name(&p, "type");
333 ff_amf_write_string(&p, "nonprivate");
335 ff_amf_write_field_name(&p, "flashVer");
336 ff_amf_write_string(&p, rt->flashver);
339 ff_amf_write_field_name(&p, "swfUrl");
340 ff_amf_write_string(&p, rt->swfurl);
343 ff_amf_write_field_name(&p, "tcUrl");
344 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
346 ff_amf_write_field_name(&p, "fpad");
347 ff_amf_write_bool(&p, 0);
348 ff_amf_write_field_name(&p, "capabilities");
349 ff_amf_write_number(&p, 15.0);
351 /* Tell the server we support all the audio codecs except
352 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
353 * which are unused in the RTMP protocol implementation. */
354 ff_amf_write_field_name(&p, "audioCodecs");
355 ff_amf_write_number(&p, 4071.0);
356 ff_amf_write_field_name(&p, "videoCodecs");
357 ff_amf_write_number(&p, 252.0);
358 ff_amf_write_field_name(&p, "videoFunction");
359 ff_amf_write_number(&p, 1.0);
362 ff_amf_write_field_name(&p, "pageUrl");
363 ff_amf_write_string(&p, rt->pageurl);
366 ff_amf_write_object_end(&p);
369 char *param = rt->conn;
371 // Write arbitrary AMF data to the Connect message.
372 while (param != NULL) {
374 param += strspn(param, " ");
377 sep = strchr(param, ' ');
380 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
381 // Invalid AMF parameter.
382 ff_rtmp_packet_destroy(&pkt);
393 pkt.size = p - pkt.data;
395 return rtmp_send_packet(rt, &pkt, 1);
398 static int read_connect(URLContext *s, RTMPContext *rt)
400 RTMPPacket pkt = { 0 };
410 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
411 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
414 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
415 if ((ret = handle_chunk_size(s, &pkt)) < 0)
418 ff_rtmp_packet_destroy(&pkt);
419 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
420 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
425 bytestream2_init(&gbc, cp, pkt.size);
426 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
427 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
428 ff_rtmp_packet_destroy(&pkt);
429 return AVERROR_INVALIDDATA;
431 if (strcmp(command, "connect")) {
432 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
433 ff_rtmp_packet_destroy(&pkt);
434 return AVERROR_INVALIDDATA;
436 ret = ff_amf_read_number(&gbc, &seqnum);
438 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
439 /* Here one could parse an AMF Object with data as flashVers and others. */
440 ret = ff_amf_get_field_value(gbc.buffer,
441 gbc.buffer + bytestream2_get_bytes_left(&gbc),
442 "app", tmpstr, sizeof(tmpstr));
444 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
445 if (!ret && strcmp(tmpstr, rt->app))
446 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
448 ff_rtmp_packet_destroy(&pkt);
450 // Send Window Acknowledgement Size (as defined in speficication)
451 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
452 RTMP_PT_SERVER_BW, 0, 4)) < 0)
455 bytestream_put_be32(&p, rt->server_bw);
456 pkt.size = p - pkt.data;
457 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
458 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
459 ff_rtmp_packet_destroy(&pkt);
462 // Send Peer Bandwidth
463 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
464 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
467 bytestream_put_be32(&p, rt->server_bw);
468 bytestream_put_byte(&p, 2); // dynamic
469 pkt.size = p - pkt.data;
470 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
471 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
472 ff_rtmp_packet_destroy(&pkt);
477 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
478 RTMP_PT_PING, 0, 6)) < 0)
482 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
483 bytestream_put_be32(&p, 0);
484 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
485 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
486 ff_rtmp_packet_destroy(&pkt);
491 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
492 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
496 bytestream_put_be32(&p, rt->out_chunk_size);
497 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
498 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
499 ff_rtmp_packet_destroy(&pkt);
503 // Send result_ NetConnection.Connect.Success to connect
504 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
506 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
510 ff_amf_write_string(&p, "_result");
511 ff_amf_write_number(&p, seqnum);
513 ff_amf_write_object_start(&p);
514 ff_amf_write_field_name(&p, "fmsVer");
515 ff_amf_write_string(&p, "FMS/3,0,1,123");
516 ff_amf_write_field_name(&p, "capabilities");
517 ff_amf_write_number(&p, 31);
518 ff_amf_write_object_end(&p);
520 ff_amf_write_object_start(&p);
521 ff_amf_write_field_name(&p, "level");
522 ff_amf_write_string(&p, "status");
523 ff_amf_write_field_name(&p, "code");
524 ff_amf_write_string(&p, "NetConnection.Connect.Success");
525 ff_amf_write_field_name(&p, "description");
526 ff_amf_write_string(&p, "Connection succeeded.");
527 ff_amf_write_field_name(&p, "objectEncoding");
528 ff_amf_write_number(&p, 0);
529 ff_amf_write_object_end(&p);
531 pkt.size = p - pkt.data;
532 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
533 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
534 ff_rtmp_packet_destroy(&pkt);
538 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
539 RTMP_PT_INVOKE, 0, 30)) < 0)
542 ff_amf_write_string(&p, "onBWDone");
543 ff_amf_write_number(&p, 0);
544 ff_amf_write_null(&p);
545 ff_amf_write_number(&p, 8192);
546 pkt.size = p - pkt.data;
547 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
548 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
549 ff_rtmp_packet_destroy(&pkt);
555 * Generate 'releaseStream' call and send it to the server. It should make
556 * the server release some channel for media streams.
558 static int gen_release_stream(URLContext *s, RTMPContext *rt)
564 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
565 0, 29 + strlen(rt->playpath))) < 0)
568 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
570 ff_amf_write_string(&p, "releaseStream");
571 ff_amf_write_number(&p, ++rt->nb_invokes);
572 ff_amf_write_null(&p);
573 ff_amf_write_string(&p, rt->playpath);
575 return rtmp_send_packet(rt, &pkt, 1);
579 * Generate 'FCPublish' call and send it to the server. It should make
580 * the server preapare for receiving media streams.
582 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
588 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
589 0, 25 + strlen(rt->playpath))) < 0)
592 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
594 ff_amf_write_string(&p, "FCPublish");
595 ff_amf_write_number(&p, ++rt->nb_invokes);
596 ff_amf_write_null(&p);
597 ff_amf_write_string(&p, rt->playpath);
599 return rtmp_send_packet(rt, &pkt, 1);
603 * Generate 'FCUnpublish' call and send it to the server. It should make
604 * the server destroy stream.
606 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
612 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
613 0, 27 + strlen(rt->playpath))) < 0)
616 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
618 ff_amf_write_string(&p, "FCUnpublish");
619 ff_amf_write_number(&p, ++rt->nb_invokes);
620 ff_amf_write_null(&p);
621 ff_amf_write_string(&p, rt->playpath);
623 return rtmp_send_packet(rt, &pkt, 0);
627 * Generate 'createStream' call and send it to the server. It should make
628 * the server allocate some channel for media streams.
630 static int gen_create_stream(URLContext *s, RTMPContext *rt)
636 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
638 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
643 ff_amf_write_string(&p, "createStream");
644 ff_amf_write_number(&p, ++rt->nb_invokes);
645 ff_amf_write_null(&p);
647 return rtmp_send_packet(rt, &pkt, 1);
652 * Generate 'deleteStream' call and send it to the server. It should make
653 * the server remove some channel for media streams.
655 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
661 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
663 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
668 ff_amf_write_string(&p, "deleteStream");
669 ff_amf_write_number(&p, ++rt->nb_invokes);
670 ff_amf_write_null(&p);
671 ff_amf_write_number(&p, rt->stream_id);
673 return rtmp_send_packet(rt, &pkt, 0);
677 * Generate client buffer time and send it to the server.
679 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
685 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
690 bytestream_put_be16(&p, 3);
691 bytestream_put_be32(&p, rt->stream_id);
692 bytestream_put_be32(&p, rt->client_buffer_time);
694 return rtmp_send_packet(rt, &pkt, 0);
698 * Generate 'play' call and send it to the server, then ping the server
699 * to start actual playing.
701 static int gen_play(URLContext *s, RTMPContext *rt)
707 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
709 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
710 0, 29 + strlen(rt->playpath))) < 0)
713 pkt.extra = rt->stream_id;
716 ff_amf_write_string(&p, "play");
717 ff_amf_write_number(&p, ++rt->nb_invokes);
718 ff_amf_write_null(&p);
719 ff_amf_write_string(&p, rt->playpath);
720 ff_amf_write_number(&p, rt->live * 1000);
722 return rtmp_send_packet(rt, &pkt, 1);
725 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
731 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
734 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
737 pkt.extra = rt->stream_id;
740 ff_amf_write_string(&p, "seek");
741 ff_amf_write_number(&p, 0); //no tracking back responses
742 ff_amf_write_null(&p); //as usual, the first null param
743 ff_amf_write_number(&p, timestamp); //where we want to jump
745 return rtmp_send_packet(rt, &pkt, 1);
749 * Generate 'publish' call and send it to the server.
751 static int gen_publish(URLContext *s, RTMPContext *rt)
757 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
759 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
760 0, 30 + strlen(rt->playpath))) < 0)
763 pkt.extra = rt->stream_id;
766 ff_amf_write_string(&p, "publish");
767 ff_amf_write_number(&p, ++rt->nb_invokes);
768 ff_amf_write_null(&p);
769 ff_amf_write_string(&p, rt->playpath);
770 ff_amf_write_string(&p, "live");
772 return rtmp_send_packet(rt, &pkt, 1);
776 * Generate ping reply and send it to the server.
778 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
784 if (ppkt->size < 6) {
785 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
787 return AVERROR_INVALIDDATA;
790 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
791 ppkt->timestamp + 1, 6)) < 0)
795 bytestream_put_be16(&p, 7);
796 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
798 return rtmp_send_packet(rt, &pkt, 0);
802 * Generate SWF verification message and send it to the server.
804 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
810 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
811 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
816 bytestream_put_be16(&p, 27);
817 memcpy(p, rt->swfverification, 42);
819 return rtmp_send_packet(rt, &pkt, 0);
823 * Generate server bandwidth message and send it to the server.
825 static int gen_server_bw(URLContext *s, RTMPContext *rt)
831 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
836 bytestream_put_be32(&p, rt->server_bw);
838 return rtmp_send_packet(rt, &pkt, 0);
842 * Generate check bandwidth message and send it to the server.
844 static int gen_check_bw(URLContext *s, RTMPContext *rt)
850 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
855 ff_amf_write_string(&p, "_checkbw");
856 ff_amf_write_number(&p, ++rt->nb_invokes);
857 ff_amf_write_null(&p);
859 return rtmp_send_packet(rt, &pkt, 1);
863 * Generate report on bytes read so far and send it to the server.
865 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
871 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
876 bytestream_put_be32(&p, rt->bytes_read);
878 return rtmp_send_packet(rt, &pkt, 0);
881 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
882 const char *subscribe)
888 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
889 0, 27 + strlen(subscribe))) < 0)
893 ff_amf_write_string(&p, "FCSubscribe");
894 ff_amf_write_number(&p, ++rt->nb_invokes);
895 ff_amf_write_null(&p);
896 ff_amf_write_string(&p, subscribe);
898 return rtmp_send_packet(rt, &pkt, 1);
901 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
902 const uint8_t *key, int keylen, uint8_t *dst)
905 uint8_t hmac_buf[64+32] = {0};
908 sha = av_sha_alloc();
910 return AVERROR(ENOMEM);
913 memcpy(hmac_buf, key, keylen);
915 av_sha_init(sha, 256);
916 av_sha_update(sha,key, keylen);
917 av_sha_final(sha, hmac_buf);
919 for (i = 0; i < 64; i++)
920 hmac_buf[i] ^= HMAC_IPAD_VAL;
922 av_sha_init(sha, 256);
923 av_sha_update(sha, hmac_buf, 64);
925 av_sha_update(sha, src, len);
926 } else { //skip 32 bytes used for storing digest
927 av_sha_update(sha, src, gap);
928 av_sha_update(sha, src + gap + 32, len - gap - 32);
930 av_sha_final(sha, hmac_buf + 64);
932 for (i = 0; i < 64; i++)
933 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
934 av_sha_init(sha, 256);
935 av_sha_update(sha, hmac_buf, 64+32);
936 av_sha_final(sha, dst);
943 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
946 int i, digest_pos = 0;
948 for (i = 0; i < 4; i++)
949 digest_pos += buf[i + off];
950 digest_pos = digest_pos % mod_val + add_val;
956 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
957 * will be stored) into that packet.
959 * @param buf handshake data (1536 bytes)
960 * @param encrypted use an encrypted connection (RTMPE)
961 * @return offset to the digest inside input data
963 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
968 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
970 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
972 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
973 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
982 * Verify that the received server response has the expected digest value.
984 * @param buf handshake data received from the server (1536 bytes)
985 * @param off position to search digest offset from
986 * @return 0 if digest is valid, digest position otherwise
988 static int rtmp_validate_digest(uint8_t *buf, int off)
993 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
995 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
996 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1001 if (!memcmp(digest, buf + digest_pos, 32))
1006 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1012 if (rt->swfhash_len != 32) {
1013 av_log(s, AV_LOG_ERROR,
1014 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1015 return AVERROR(EINVAL);
1018 p = &rt->swfverification[0];
1019 bytestream_put_byte(&p, 1);
1020 bytestream_put_byte(&p, 1);
1021 bytestream_put_be32(&p, rt->swfsize);
1022 bytestream_put_be32(&p, rt->swfsize);
1024 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1031 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1032 uint8_t **out_data, int64_t *out_size)
1034 z_stream zs = { 0 };
1039 zs.avail_in = in_size;
1040 zs.next_in = in_data;
1041 ret = inflateInit(&zs);
1043 return AVERROR_UNKNOWN;
1046 uint8_t tmp_buf[16384];
1048 zs.avail_out = sizeof(tmp_buf);
1049 zs.next_out = tmp_buf;
1051 ret = inflate(&zs, Z_NO_FLUSH);
1052 if (ret != Z_OK && ret != Z_STREAM_END) {
1053 ret = AVERROR_UNKNOWN;
1057 size = sizeof(tmp_buf) - zs.avail_out;
1058 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1059 ret = AVERROR(ENOMEM);
1064 memcpy(*out_data + *out_size, tmp_buf, size);
1066 } while (zs.avail_out == 0);
1074 static int rtmp_calc_swfhash(URLContext *s)
1076 RTMPContext *rt = s->priv_data;
1077 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1078 int64_t in_size, out_size;
1084 /* Get the SWF player file. */
1085 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1086 &s->interrupt_callback, NULL)) < 0) {
1087 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1091 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1096 if (!(in_data = av_malloc(in_size))) {
1097 ret = AVERROR(ENOMEM);
1101 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1105 ret = AVERROR_INVALIDDATA;
1109 if (!memcmp(in_data, "CWS", 3)) {
1110 /* Decompress the SWF player file using Zlib. */
1111 if (!(out_data = av_malloc(8))) {
1112 ret = AVERROR(ENOMEM);
1115 *in_data = 'F'; // magic stuff
1116 memcpy(out_data, in_data, 8);
1120 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1121 &out_data, &out_size)) < 0)
1124 av_log(s, AV_LOG_ERROR,
1125 "Zlib is required for decompressing the SWF player file.\n");
1126 ret = AVERROR(EINVAL);
1136 /* Compute the SHA256 hash of the SWF player file. */
1137 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1138 "Genuine Adobe Flash Player 001", 30,
1142 /* Set SWFVerification parameters. */
1143 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1144 rt->swfsize = swfsize;
1148 av_freep(&out_data);
1149 ffurl_close(stream);
1154 * Perform handshake with the server by means of exchanging pseudorandom data
1155 * signed with HMAC-SHA2 digest.
1157 * @return 0 if handshake succeeds, negative value otherwise
1159 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1162 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1163 3, // unencrypted data
1164 0, 0, 0, 0, // client uptime
1170 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1171 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1173 int server_pos, client_pos;
1174 uint8_t digest[32], signature[32];
1177 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1179 av_lfg_init(&rnd, 0xDEADC0DE);
1180 // generate handshake packet - 1536 bytes of pseudorandom data
1181 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1182 tosend[i] = av_lfg_get(&rnd) >> 24;
1184 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1185 /* When the client wants to use RTMPE, we have to change the command
1186 * byte to 0x06 which means to use encrypted data and we have to set
1187 * the flash version to at least 9.0.115.0. */
1194 /* Initialize the Diffie-Hellmann context and generate the public key
1195 * to send to the server. */
1196 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1200 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1204 if ((ret = ffurl_write(rt->stream, tosend,
1205 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1206 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1210 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1211 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1212 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1216 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1217 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1218 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1222 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1223 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1224 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1226 if (rt->is_input && serverdata[5] >= 3) {
1227 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1233 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1238 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1239 return AVERROR(EIO);
1243 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1244 * key are the last 32 bytes of the server handshake. */
1246 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1247 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1251 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1252 rtmp_server_key, sizeof(rtmp_server_key),
1257 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1258 0, digest, 32, signature);
1262 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1263 /* Compute the shared secret key sent by the server and initialize
1264 * the RC4 encryption. */
1265 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1266 tosend + 1, type)) < 0)
1269 /* Encrypt the signature received by the server. */
1270 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1273 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1274 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1275 return AVERROR(EIO);
1278 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1279 tosend[i] = av_lfg_get(&rnd) >> 24;
1280 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1281 rtmp_player_key, sizeof(rtmp_player_key),
1286 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1288 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1292 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1293 /* Encrypt the signature to be send to the server. */
1294 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1295 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1299 // write reply back to the server
1300 if ((ret = ffurl_write(rt->stream, tosend,
1301 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1304 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1305 /* Set RC4 keys for encryption and update the keystreams. */
1306 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1310 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1311 /* Compute the shared secret key sent by the server and initialize
1312 * the RC4 encryption. */
1313 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1314 tosend + 1, 1)) < 0)
1317 if (serverdata[0] == 9) {
1318 /* Encrypt the signature received by the server. */
1319 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1324 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1325 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1328 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1329 /* Set RC4 keys for encryption and update the keystreams. */
1330 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1338 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1339 uint32_t *second_int, char *arraydata,
1344 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1345 RTMP_HANDSHAKE_PACKET_SIZE);
1347 return AVERROR(EIO);
1348 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1349 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1350 " not following standard\n", (int)inoutsize);
1351 return AVERROR(EINVAL);
1354 *first_int = AV_RB32(arraydata);
1355 *second_int = AV_RB32(arraydata + 4);
1359 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1360 uint32_t second_int, char *arraydata, int size)
1364 AV_WB32(arraydata, first_int);
1365 AV_WB32(arraydata + 4, second_int);
1366 inoutsize = ffurl_write(rt->stream, arraydata,
1367 RTMP_HANDSHAKE_PACKET_SIZE);
1368 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1369 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1370 return AVERROR(EIO);
1377 * rtmp handshake server side
1379 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1381 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1383 uint32_t hs_my_epoch;
1384 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1385 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1392 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1393 if (inoutsize <= 0) {
1394 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1395 return AVERROR(EIO);
1398 if (buffer[0] != 3) {
1399 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1400 return AVERROR(EIO);
1402 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1403 av_log(s, AV_LOG_ERROR,
1404 "Unable to write answer - RTMP S0\n");
1405 return AVERROR(EIO);
1408 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1409 RTMP_HANDSHAKE_PACKET_SIZE);
1411 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1415 /* By now same epoch will be sent */
1416 hs_my_epoch = hs_epoch;
1417 /* Generate random */
1418 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1420 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1422 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1423 RTMP_HANDSHAKE_PACKET_SIZE);
1425 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1429 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1430 RTMP_HANDSHAKE_PACKET_SIZE);
1432 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1436 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1437 RTMP_HANDSHAKE_PACKET_SIZE);
1439 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1442 if (temp != hs_my_epoch)
1443 av_log(s, AV_LOG_WARNING,
1444 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1445 if (memcmp(buffer + 8, hs_s1 + 8,
1446 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1447 av_log(s, AV_LOG_WARNING,
1448 "Erroneous C2 Message random does not match up\n");
1453 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1455 RTMPContext *rt = s->priv_data;
1458 if (pkt->size < 4) {
1459 av_log(s, AV_LOG_ERROR,
1460 "Too short chunk size change packet (%d)\n",
1462 return AVERROR_INVALIDDATA;
1465 if (!rt->is_input) {
1466 /* Send the same chunk size change packet back to the server,
1467 * setting the outgoing chunk size to the same as the incoming one. */
1468 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1469 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1471 rt->out_chunk_size = AV_RB32(pkt->data);
1474 rt->in_chunk_size = AV_RB32(pkt->data);
1475 if (rt->in_chunk_size <= 0) {
1476 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1478 return AVERROR_INVALIDDATA;
1480 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1486 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1488 RTMPContext *rt = s->priv_data;
1491 if (pkt->size < 2) {
1492 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1494 return AVERROR_INVALIDDATA;
1497 t = AV_RB16(pkt->data);
1499 if ((ret = gen_pong(s, rt, pkt)) < 0)
1501 } else if (t == 26) {
1503 if ((ret = gen_swf_verification(s, rt)) < 0)
1506 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1513 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1515 RTMPContext *rt = s->priv_data;
1517 if (pkt->size < 4) {
1518 av_log(s, AV_LOG_ERROR,
1519 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1521 return AVERROR_INVALIDDATA;
1524 rt->client_report_size = AV_RB32(pkt->data);
1525 if (rt->client_report_size <= 0) {
1526 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1527 rt->client_report_size);
1528 return AVERROR_INVALIDDATA;
1531 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1532 rt->client_report_size >>= 1;
1537 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1539 RTMPContext *rt = s->priv_data;
1541 if (pkt->size < 4) {
1542 av_log(s, AV_LOG_ERROR,
1543 "Too short server bandwidth report packet (%d)\n",
1545 return AVERROR_INVALIDDATA;
1548 rt->server_bw = AV_RB32(pkt->data);
1549 if (rt->server_bw <= 0) {
1550 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1552 return AVERROR_INVALIDDATA;
1554 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1559 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1560 const char *opaque, const char *challenge)
1563 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1564 struct AVMD5 *md5 = av_md5_alloc();
1566 return AVERROR(ENOMEM);
1568 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1571 av_md5_update(md5, user, strlen(user));
1572 av_md5_update(md5, salt, strlen(salt));
1573 av_md5_update(md5, rt->password, strlen(rt->password));
1574 av_md5_final(md5, hash);
1575 av_base64_encode(hashstr, sizeof(hashstr), hash,
1578 av_md5_update(md5, hashstr, strlen(hashstr));
1580 av_md5_update(md5, opaque, strlen(opaque));
1582 av_md5_update(md5, challenge, strlen(challenge));
1583 av_md5_update(md5, challenge2, strlen(challenge2));
1584 av_md5_final(md5, hash);
1585 av_base64_encode(hashstr, sizeof(hashstr), hash,
1587 snprintf(rt->auth_params, sizeof(rt->auth_params),
1588 "?authmod=%s&user=%s&challenge=%s&response=%s",
1589 "adobe", user, challenge2, hashstr);
1591 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1592 "&opaque=%s", opaque);
1598 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1601 char hashstr1[33], hashstr2[33];
1602 const char *realm = "live";
1603 const char *method = "publish";
1604 const char *qop = "auth";
1605 const char *nc = "00000001";
1607 struct AVMD5 *md5 = av_md5_alloc();
1609 return AVERROR(ENOMEM);
1611 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1614 av_md5_update(md5, user, strlen(user));
1615 av_md5_update(md5, ":", 1);
1616 av_md5_update(md5, realm, strlen(realm));
1617 av_md5_update(md5, ":", 1);
1618 av_md5_update(md5, rt->password, strlen(rt->password));
1619 av_md5_final(md5, hash);
1620 ff_data_to_hex(hashstr1, hash, 16, 1);
1621 hashstr1[32] = '\0';
1624 av_md5_update(md5, method, strlen(method));
1625 av_md5_update(md5, ":/", 2);
1626 av_md5_update(md5, rt->app, strlen(rt->app));
1627 if (!strchr(rt->app, '/'))
1628 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1629 av_md5_final(md5, hash);
1630 ff_data_to_hex(hashstr2, hash, 16, 1);
1631 hashstr2[32] = '\0';
1634 av_md5_update(md5, hashstr1, strlen(hashstr1));
1635 av_md5_update(md5, ":", 1);
1637 av_md5_update(md5, nonce, strlen(nonce));
1638 av_md5_update(md5, ":", 1);
1639 av_md5_update(md5, nc, strlen(nc));
1640 av_md5_update(md5, ":", 1);
1641 av_md5_update(md5, cnonce, strlen(cnonce));
1642 av_md5_update(md5, ":", 1);
1643 av_md5_update(md5, qop, strlen(qop));
1644 av_md5_update(md5, ":", 1);
1645 av_md5_update(md5, hashstr2, strlen(hashstr2));
1646 av_md5_final(md5, hash);
1647 ff_data_to_hex(hashstr1, hash, 16, 1);
1649 snprintf(rt->auth_params, sizeof(rt->auth_params),
1650 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1651 "llnw", user, nonce, cnonce, nc, hashstr1);
1657 static int handle_connect_error(URLContext *s, const char *desc)
1659 RTMPContext *rt = s->priv_data;
1660 char buf[300], *ptr, authmod[15];
1662 const char *user = "", *salt = "", *opaque = NULL,
1663 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1665 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1666 !(cptr = strstr(desc, "authmod=llnw"))) {
1667 av_log(s, AV_LOG_ERROR,
1668 "Unknown connect error (unsupported authentication method?)\n");
1669 return AVERROR_UNKNOWN;
1671 cptr += strlen("authmod=");
1672 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1673 authmod[i++] = *cptr++;
1676 if (!rt->username[0] || !rt->password[0]) {
1677 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1678 return AVERROR_UNKNOWN;
1681 if (strstr(desc, "?reason=authfailed")) {
1682 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1683 return AVERROR_UNKNOWN;
1684 } else if (strstr(desc, "?reason=nosuchuser")) {
1685 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1686 return AVERROR_UNKNOWN;
1689 if (rt->auth_tried) {
1690 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1691 return AVERROR_UNKNOWN;
1694 rt->auth_params[0] = '\0';
1696 if (strstr(desc, "code=403 need auth")) {
1697 snprintf(rt->auth_params, sizeof(rt->auth_params),
1698 "?authmod=%s&user=%s", authmod, rt->username);
1702 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1703 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1704 return AVERROR_UNKNOWN;
1707 av_strlcpy(buf, cptr + 1, sizeof(buf));
1711 char *next = strchr(ptr, '&');
1712 char *value = strchr(ptr, '=');
1717 if (!strcmp(ptr, "user")) {
1719 } else if (!strcmp(ptr, "salt")) {
1721 } else if (!strcmp(ptr, "opaque")) {
1723 } else if (!strcmp(ptr, "challenge")) {
1725 } else if (!strcmp(ptr, "nonce")) {
1728 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1731 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1736 if (!strcmp(authmod, "adobe")) {
1737 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1740 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1748 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1750 RTMPContext *rt = s->priv_data;
1751 const uint8_t *data_end = pkt->data + pkt->size;
1752 char *tracked_method = NULL;
1753 int level = AV_LOG_ERROR;
1754 uint8_t tmpstr[256];
1757 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1760 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1761 "description", tmpstr, sizeof(tmpstr))) {
1762 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1763 !strcmp(tracked_method, "releaseStream") ||
1764 !strcmp(tracked_method, "FCSubscribe") ||
1765 !strcmp(tracked_method, "FCPublish"))) {
1766 /* Gracefully ignore Adobe-specific historical artifact errors. */
1767 level = AV_LOG_WARNING;
1769 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1770 ret = handle_connect_error(s, tmpstr);
1772 rt->do_reconnect = 1;
1773 level = AV_LOG_VERBOSE;
1776 ret = AVERROR_UNKNOWN;
1777 av_log(s, level, "Server error: %s\n", tmpstr);
1780 av_free(tracked_method);
1784 static int write_begin(URLContext *s)
1786 RTMPContext *rt = s->priv_data;
1788 RTMPPacket spkt = { 0 };
1791 // Send Stream Begin 1
1792 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1793 RTMP_PT_PING, 0, 6)) < 0) {
1794 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1798 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1799 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1800 bytestream2_put_be32(&pbc, rt->nb_streamid);
1802 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1803 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1805 ff_rtmp_packet_destroy(&spkt);
1810 static int write_status(URLContext *s, RTMPPacket *pkt,
1811 const char *status, const char *filename)
1813 RTMPContext *rt = s->priv_data;
1814 RTMPPacket spkt = { 0 };
1815 char statusmsg[128];
1819 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1821 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1822 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1827 spkt.extra = pkt->extra;
1828 ff_amf_write_string(&pp, "onStatus");
1829 ff_amf_write_number(&pp, 0);
1830 ff_amf_write_null(&pp);
1832 ff_amf_write_object_start(&pp);
1833 ff_amf_write_field_name(&pp, "level");
1834 ff_amf_write_string(&pp, "status");
1835 ff_amf_write_field_name(&pp, "code");
1836 ff_amf_write_string(&pp, status);
1837 ff_amf_write_field_name(&pp, "description");
1838 snprintf(statusmsg, sizeof(statusmsg),
1839 "%s is now published", filename);
1840 ff_amf_write_string(&pp, statusmsg);
1841 ff_amf_write_field_name(&pp, "details");
1842 ff_amf_write_string(&pp, filename);
1843 ff_amf_write_field_name(&pp, "clientid");
1844 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1845 ff_amf_write_string(&pp, statusmsg);
1846 ff_amf_write_object_end(&pp);
1848 spkt.size = pp - spkt.data;
1849 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1850 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1851 ff_rtmp_packet_destroy(&spkt);
1856 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1858 RTMPContext *rt = s->priv_data;
1864 const uint8_t *p = pkt->data;
1866 RTMPPacket spkt = { 0 };
1870 bytestream2_init(&gbc, p, pkt->size);
1871 if (ff_amf_read_string(&gbc, command, sizeof(command),
1873 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1874 return AVERROR_INVALIDDATA;
1877 ret = ff_amf_read_number(&gbc, &seqnum);
1880 ret = ff_amf_read_null(&gbc);
1883 if (!strcmp(command, "FCPublish") ||
1884 !strcmp(command, "publish")) {
1885 ret = ff_amf_read_string(&gbc, filename,
1886 sizeof(filename), &stringlen);
1889 pchar = strrchr(s->filename, '/');
1891 av_log(s, AV_LOG_WARNING,
1892 "Unable to find / in url %s, bad format\n",
1894 pchar = s->filename;
1897 if (strcmp(pchar, filename))
1898 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1899 " %s\n", filename, pchar);
1901 rt->state = STATE_RECEIVING;
1904 if (!strcmp(command, "FCPublish")) {
1905 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1907 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1908 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1912 ff_amf_write_string(&pp, "onFCPublish");
1913 } else if (!strcmp(command, "publish")) {
1914 ret = write_begin(s);
1918 // Send onStatus(NetStream.Publish.Start)
1919 return write_status(s, pkt, "NetStream.Publish.Start",
1921 } else if (!strcmp(command, "play")) {
1922 ret = write_begin(s);
1925 rt->state = STATE_SENDING;
1926 return write_status(s, pkt, "NetStream.Play.Start",
1929 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1931 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1932 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1936 ff_amf_write_string(&pp, "_result");
1937 ff_amf_write_number(&pp, seqnum);
1938 ff_amf_write_null(&pp);
1939 if (!strcmp(command, "createStream")) {
1941 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1942 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1943 ff_amf_write_number(&pp, rt->nb_streamid);
1944 /* By now we don't control which streams are removed in
1945 * deleteStream. There is no stream creation control
1946 * if a client creates more than 2^32 - 2 streams. */
1949 spkt.size = pp - spkt.data;
1950 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1951 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1952 ff_rtmp_packet_destroy(&spkt);
1956 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1958 RTMPContext *rt = s->priv_data;
1959 char *tracked_method = NULL;
1962 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
1965 if (!tracked_method) {
1966 /* Ignore this reply when the current method is not tracked. */
1970 if (!strcmp(tracked_method, "connect")) {
1971 if (!rt->is_input) {
1972 if ((ret = gen_release_stream(s, rt)) < 0)
1975 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1978 if ((ret = gen_server_bw(s, rt)) < 0)
1982 if ((ret = gen_create_stream(s, rt)) < 0)
1986 /* Send the FCSubscribe command when the name of live
1987 * stream is defined by the user or if it's a live stream. */
1988 if (rt->subscribe) {
1989 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1991 } else if (rt->live == -1) {
1992 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1996 } else if (!strcmp(tracked_method, "createStream")) {
1997 //extract a number from the result
1998 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1999 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2001 rt->stream_id = av_int2double(AV_RB64(pkt->data + 21));
2004 if (!rt->is_input) {
2005 if ((ret = gen_publish(s, rt)) < 0)
2008 if ((ret = gen_play(s, rt)) < 0)
2010 if ((ret = gen_buffer_time(s, rt)) < 0)
2016 av_free(tracked_method);
2020 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2022 RTMPContext *rt = s->priv_data;
2023 const uint8_t *data_end = pkt->data + pkt->size;
2024 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2025 uint8_t tmpstr[256];
2028 for (i = 0; i < 2; i++) {
2029 t = ff_amf_tag_size(ptr, data_end);
2035 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2036 if (!t && !strcmp(tmpstr, "error")) {
2037 t = ff_amf_get_field_value(ptr, data_end,
2038 "description", tmpstr, sizeof(tmpstr));
2039 if (t || !tmpstr[0])
2040 t = ff_amf_get_field_value(ptr, data_end, "code",
2041 tmpstr, sizeof(tmpstr));
2043 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2047 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2048 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2049 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2050 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2051 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2052 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2057 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2059 RTMPContext *rt = s->priv_data;
2062 //TODO: check for the messages sent for wrong state?
2063 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2064 if ((ret = handle_invoke_error(s, pkt)) < 0)
2066 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2067 if ((ret = handle_invoke_result(s, pkt)) < 0)
2069 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2070 if ((ret = handle_invoke_status(s, pkt)) < 0)
2072 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2073 if ((ret = gen_check_bw(s, rt)) < 0)
2075 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2076 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2077 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2078 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2079 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2080 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2081 if ((ret = send_invoke_response(s, pkt)) < 0)
2088 static int update_offset(RTMPContext *rt, int size)
2092 // generate packet header and put data into buffer for FLV demuxer
2093 if (rt->flv_off < rt->flv_size) {
2094 // There is old unread data in the buffer, thus append at the end
2095 old_flv_size = rt->flv_size;
2096 rt->flv_size += size;
2098 // All data has been read, write the new data at the start of the buffer
2100 rt->flv_size = size;
2104 return old_flv_size;
2107 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2109 int old_flv_size, ret;
2111 const uint8_t *data = pkt->data + skip;
2112 const int size = pkt->size - skip;
2113 uint32_t ts = pkt->timestamp;
2115 old_flv_size = update_offset(rt, size + 15);
2117 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2118 rt->flv_size = rt->flv_off = 0;
2121 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2122 bytestream2_skip_p(&pbc, old_flv_size);
2123 bytestream2_put_byte(&pbc, pkt->type);
2124 bytestream2_put_be24(&pbc, size);
2125 bytestream2_put_be24(&pbc, ts);
2126 bytestream2_put_byte(&pbc, ts >> 24);
2127 bytestream2_put_be24(&pbc, 0);
2128 bytestream2_put_buffer(&pbc, data, size);
2129 bytestream2_put_be32(&pbc, 0);
2134 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2136 RTMPContext *rt = s->priv_data;
2137 uint8_t commandbuffer[64];
2138 char statusmsg[128];
2139 int stringlen, ret, skip = 0;
2142 bytestream2_init(&gbc, pkt->data, pkt->size);
2143 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2145 return AVERROR_INVALIDDATA;
2147 // Skip the @setDataFrame string and validate it is a notification
2148 if (!strcmp(commandbuffer, "@setDataFrame")) {
2149 skip = gbc.buffer - pkt->data;
2150 ret = ff_amf_read_string(&gbc, statusmsg,
2151 sizeof(statusmsg), &stringlen);
2153 return AVERROR_INVALIDDATA;
2156 return append_flv_data(rt, pkt, skip);
2160 * Parse received packet and possibly perform some action depending on
2161 * the packet contents.
2162 * @return 0 for no errors, negative values for serious errors which prevent
2163 * further communications, positive values for uncritical errors
2165 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2170 ff_rtmp_packet_dump(s, pkt);
2173 switch (pkt->type) {
2174 case RTMP_PT_BYTES_READ:
2175 av_dlog(s, "received bytes read report\n");
2177 case RTMP_PT_CHUNK_SIZE:
2178 if ((ret = handle_chunk_size(s, pkt)) < 0)
2182 if ((ret = handle_ping(s, pkt)) < 0)
2185 case RTMP_PT_CLIENT_BW:
2186 if ((ret = handle_client_bw(s, pkt)) < 0)
2189 case RTMP_PT_SERVER_BW:
2190 if ((ret = handle_server_bw(s, pkt)) < 0)
2193 case RTMP_PT_INVOKE:
2194 if ((ret = handle_invoke(s, pkt)) < 0)
2199 case RTMP_PT_METADATA:
2200 case RTMP_PT_NOTIFY:
2201 /* Audio, Video and Metadata packets are parsed in get_packet() */
2204 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2210 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2212 int ret, old_flv_size, type;
2213 const uint8_t *next;
2216 uint32_t ts, cts, pts = 0;
2218 old_flv_size = update_offset(rt, pkt->size);
2220 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2221 rt->flv_size = rt->flv_off = 0;
2226 p = rt->flv_data + old_flv_size;
2228 /* copy data while rewriting timestamps */
2229 ts = pkt->timestamp;
2231 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2232 type = bytestream_get_byte(&next);
2233 size = bytestream_get_be24(&next);
2234 cts = bytestream_get_be24(&next);
2235 cts |= bytestream_get_byte(&next) << 24;
2240 if (size + 3 + 4 > pkt->data + pkt->size - next)
2242 bytestream_put_byte(&p, type);
2243 bytestream_put_be24(&p, size);
2244 bytestream_put_be24(&p, ts);
2245 bytestream_put_byte(&p, ts >> 24);
2246 memcpy(p, next, size + 3 + 4);
2247 next += size + 3 + 4;
2250 if (p != rt->flv_data + rt->flv_size) {
2251 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2252 "RTMP_PT_METADATA packet\n");
2253 rt->flv_size = p - rt->flv_data;
2260 * Interact with the server by receiving and sending RTMP packets until
2261 * there is some significant data (media data or expected status notification).
2263 * @param s reading context
2264 * @param for_header non-zero value tells function to work until it
2265 * gets notification from the server that playing has been started,
2266 * otherwise function will work until some media data is received (or
2268 * @return 0 for successful operation, negative value in case of error
2270 static int get_packet(URLContext *s, int for_header)
2272 RTMPContext *rt = s->priv_data;
2275 if (rt->state == STATE_STOPPED)
2279 RTMPPacket rpkt = { 0 };
2280 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2281 rt->in_chunk_size, &rt->prev_pkt[0],
2282 &rt->nb_prev_pkt[0])) <= 0) {
2284 return AVERROR(EAGAIN);
2286 return AVERROR(EIO);
2289 rt->bytes_read += ret;
2290 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2291 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2292 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2294 rt->last_bytes_read = rt->bytes_read;
2297 ret = rtmp_parse_result(s, rt, &rpkt);
2299 // At this point we must check if we are in the seek state and continue
2300 // with the next packet. handle_invoke will get us out of this state
2301 // when the right message is encountered
2302 if (rt->state == STATE_SEEKING) {
2303 ff_rtmp_packet_destroy(&rpkt);
2304 // We continue, let the natural flow of things happen:
2305 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2309 if (ret < 0) {//serious error in current packet
2310 ff_rtmp_packet_destroy(&rpkt);
2313 if (rt->do_reconnect && for_header) {
2314 ff_rtmp_packet_destroy(&rpkt);
2317 if (rt->state == STATE_STOPPED) {
2318 ff_rtmp_packet_destroy(&rpkt);
2321 if (for_header && (rt->state == STATE_PLAYING ||
2322 rt->state == STATE_PUBLISHING ||
2323 rt->state == STATE_SENDING ||
2324 rt->state == STATE_RECEIVING)) {
2325 ff_rtmp_packet_destroy(&rpkt);
2328 if (!rpkt.size || !rt->is_input) {
2329 ff_rtmp_packet_destroy(&rpkt);
2332 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2333 ret = append_flv_data(rt, &rpkt, 0);
2334 ff_rtmp_packet_destroy(&rpkt);
2336 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2337 ret = handle_notify(s, &rpkt);
2338 ff_rtmp_packet_destroy(&rpkt);
2340 } else if (rpkt.type == RTMP_PT_METADATA) {
2341 ret = handle_metadata(rt, &rpkt);
2342 ff_rtmp_packet_destroy(&rpkt);
2345 ff_rtmp_packet_destroy(&rpkt);
2349 static int rtmp_close(URLContext *h)
2351 RTMPContext *rt = h->priv_data;
2354 if (!rt->is_input) {
2355 rt->flv_data = NULL;
2356 if (rt->out_pkt.size)
2357 ff_rtmp_packet_destroy(&rt->out_pkt);
2358 if (rt->state > STATE_FCPUBLISH)
2359 ret = gen_fcunpublish_stream(h, rt);
2361 if (rt->state > STATE_HANDSHAKED)
2362 ret = gen_delete_stream(h, rt);
2363 for (i = 0; i < 2; i++) {
2364 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2365 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2366 av_freep(&rt->prev_pkt[i]);
2369 free_tracked_methods(rt);
2370 av_freep(&rt->flv_data);
2371 ffurl_close(rt->stream);
2376 * Open RTMP connection and verify that the stream can be played.
2378 * URL syntax: rtmp://server[:port][/app][/playpath]
2379 * where 'app' is first one or two directories in the path
2380 * (e.g. /ondemand/, /flash/live/, etc.)
2381 * and 'playpath' is a file name (the rest of the path,
2382 * may be prefixed with "mp4:")
2384 static int rtmp_open(URLContext *s, const char *uri, int flags)
2386 RTMPContext *rt = s->priv_data;
2387 char proto[8], hostname[256], path[1024], auth[100], *fname;
2388 char *old_app, *qmark, fname_buffer[1024];
2391 AVDictionary *opts = NULL;
2394 if (rt->listen_timeout > 0)
2397 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2399 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2400 hostname, sizeof(hostname), &port,
2401 path, sizeof(path), s->filename);
2403 if (strchr(path, ' ')) {
2404 av_log(s, AV_LOG_WARNING,
2405 "Detected librtmp style URL parameters, these aren't supported "
2406 "by the libavformat internal RTMP handler currently enabled. "
2407 "See the documentation for the correct way to pass parameters.\n");
2411 char *ptr = strchr(auth, ':');
2414 av_strlcpy(rt->username, auth, sizeof(rt->username));
2415 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2419 if (rt->listen && strcmp(proto, "rtmp")) {
2420 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2422 return AVERROR(EINVAL);
2424 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2425 if (!strcmp(proto, "rtmpts"))
2426 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2428 /* open the http tunneling connection */
2429 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2430 } else if (!strcmp(proto, "rtmps")) {
2431 /* open the tls connection */
2433 port = RTMPS_DEFAULT_PORT;
2434 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2435 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2436 if (!strcmp(proto, "rtmpte"))
2437 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2439 /* open the encrypted connection */
2440 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2443 /* open the tcp connection */
2445 port = RTMP_DEFAULT_PORT;
2447 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2448 "?listen&listen_timeout=%d",
2449 rt->listen_timeout * 1000);
2451 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2455 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2456 &s->interrupt_callback, &opts)) < 0) {
2457 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2461 if (rt->swfverify) {
2462 if ((ret = rtmp_calc_swfhash(s)) < 0)
2466 rt->state = STATE_START;
2467 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2469 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2472 rt->out_chunk_size = 128;
2473 rt->in_chunk_size = 128; // Probably overwritten later
2474 rt->state = STATE_HANDSHAKED;
2476 // Keep the application name when it has been defined by the user.
2479 rt->app = av_malloc(APP_MAX_LENGTH);
2481 ret = AVERROR(ENOMEM);
2485 //extract "app" part from path
2486 qmark = strchr(path, '?');
2487 if (qmark && strstr(qmark, "slist=")) {
2489 // After slist we have the playpath, before the params, the app
2490 av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH));
2491 fname = strstr(path, "slist=") + 6;
2492 // Strip any further query parameters from fname
2493 amp = strchr(fname, '&');
2495 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2496 sizeof(fname_buffer)));
2497 fname = fname_buffer;
2499 } else if (!strncmp(path, "/ondemand/", 10)) {
2501 memcpy(rt->app, "ondemand", 9);
2503 char *next = *path ? path + 1 : path;
2504 char *p = strchr(next, '/');
2509 // make sure we do not mismatch a playpath for an application instance
2510 char *c = strchr(p + 1, ':');
2511 fname = strchr(p + 1, '/');
2512 if (!fname || (c && c < fname)) {
2514 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2517 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2523 // The name of application has been defined by the user, override it.
2524 if (strlen(old_app) >= APP_MAX_LENGTH) {
2525 ret = AVERROR(EINVAL);
2532 if (!rt->playpath) {
2533 int len = strlen(fname);
2535 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2536 if (!rt->playpath) {
2537 ret = AVERROR(ENOMEM);
2541 if (!strchr(fname, ':') && len >= 4 &&
2542 (!strcmp(fname + len - 4, ".f4v") ||
2543 !strcmp(fname + len - 4, ".mp4"))) {
2544 memcpy(rt->playpath, "mp4:", 5);
2546 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2547 fname[len - 4] = '\0';
2548 rt->playpath[0] = 0;
2550 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2554 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2556 ret = AVERROR(ENOMEM);
2559 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2560 port, "/%s", rt->app);
2563 if (!rt->flashver) {
2564 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2565 if (!rt->flashver) {
2566 ret = AVERROR(ENOMEM);
2570 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2571 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2572 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2574 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2575 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2579 rt->client_report_size = 1048576;
2581 rt->last_bytes_read = 0;
2582 rt->server_bw = 2500000;
2584 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2585 proto, path, rt->app, rt->playpath);
2587 if ((ret = gen_connect(s, rt)) < 0)
2590 if ((ret = read_connect(s, s->priv_data)) < 0)
2595 ret = get_packet(s, 1);
2596 } while (ret == AVERROR(EAGAIN));
2600 if (rt->do_reconnect) {
2602 ffurl_close(rt->stream);
2604 rt->do_reconnect = 0;
2606 for (i = 0; i < 2; i++)
2607 memset(rt->prev_pkt[i], 0,
2608 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2609 free_tracked_methods(rt);
2615 // generate FLV header for demuxer
2617 if ((err = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2620 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
2623 rt->flv_data = NULL;
2625 rt->skip_bytes = 13;
2628 s->max_packet_size = rt->stream->max_packet_size;
2633 av_dict_free(&opts);
2638 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2640 RTMPContext *rt = s->priv_data;
2641 int orig_size = size;
2645 int data_left = rt->flv_size - rt->flv_off;
2647 if (data_left >= size) {
2648 memcpy(buf, rt->flv_data + rt->flv_off, size);
2649 rt->flv_off += size;
2652 if (data_left > 0) {
2653 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2656 rt->flv_off = rt->flv_size;
2659 if ((ret = get_packet(s, 0)) < 0)
2665 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2668 RTMPContext *rt = s->priv_data;
2670 av_log(s, AV_LOG_DEBUG,
2671 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2672 stream_index, timestamp, flags);
2673 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2674 av_log(s, AV_LOG_ERROR,
2675 "Unable to send seek command on stream index %d at timestamp "
2676 "%"PRId64" with flags %08x\n",
2677 stream_index, timestamp, flags);
2680 rt->flv_off = rt->flv_size;
2681 rt->state = STATE_SEEKING;
2685 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2687 RTMPContext *rt = s->priv_data;
2688 int size_temp = size;
2689 int pktsize, pkttype;
2691 const uint8_t *buf_temp = buf;
2696 if (rt->skip_bytes) {
2697 int skip = FFMIN(rt->skip_bytes, size_temp);
2700 rt->skip_bytes -= skip;
2704 if (rt->flv_header_bytes < RTMP_HEADER) {
2705 const uint8_t *header = rt->flv_header;
2706 int copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2707 int channel = RTMP_AUDIO_CHANNEL;
2708 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2709 rt->flv_header_bytes += copy;
2711 if (rt->flv_header_bytes < RTMP_HEADER)
2714 pkttype = bytestream_get_byte(&header);
2715 pktsize = bytestream_get_be24(&header);
2716 ts = bytestream_get_be24(&header);
2717 ts |= bytestream_get_byte(&header) << 24;
2718 bytestream_get_be24(&header);
2719 rt->flv_size = pktsize;
2721 if (pkttype == RTMP_PT_VIDEO)
2722 channel = RTMP_VIDEO_CHANNEL;
2724 //force 12bytes header
2725 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2726 pkttype == RTMP_PT_NOTIFY) {
2727 if (pkttype == RTMP_PT_NOTIFY)
2729 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2730 &rt->nb_prev_pkt[1],
2733 rt->prev_pkt[1][channel].channel_id = 0;
2736 //this can be a big packet, it's better to send it right here
2737 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2738 pkttype, ts, pktsize)) < 0)
2741 rt->out_pkt.extra = rt->stream_id;
2742 rt->flv_data = rt->out_pkt.data;
2744 if (pkttype == RTMP_PT_NOTIFY)
2745 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
2748 if (rt->flv_size - rt->flv_off > size_temp) {
2749 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
2750 rt->flv_off += size_temp;
2753 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
2754 size_temp -= rt->flv_size - rt->flv_off;
2755 rt->flv_off += rt->flv_size - rt->flv_off;
2758 if (rt->flv_off == rt->flv_size) {
2761 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
2765 rt->flv_header_bytes = 0;
2766 rt->flv_nb_packets++;
2768 } while (buf_temp - buf < size);
2770 if (rt->flv_nb_packets < rt->flush_interval)
2772 rt->flv_nb_packets = 0;
2774 /* set stream into nonblocking mode */
2775 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
2777 /* try to read one byte from the stream */
2778 ret = ffurl_read(rt->stream, &c, 1);
2780 /* switch the stream back into blocking mode */
2781 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
2783 if (ret == AVERROR(EAGAIN)) {
2784 /* no incoming data to handle */
2786 } else if (ret < 0) {
2788 } else if (ret == 1) {
2789 RTMPPacket rpkt = { 0 };
2791 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
2794 &rt->nb_prev_pkt[0], c)) <= 0)
2797 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
2800 ff_rtmp_packet_destroy(&rpkt);
2806 #define OFFSET(x) offsetof(RTMPContext, x)
2807 #define DEC AV_OPT_FLAG_DECODING_PARAM
2808 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2810 static const AVOption rtmp_options[] = {
2811 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2812 {"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},
2813 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2814 {"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},
2815 {"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},
2816 {"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"},
2817 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
2818 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
2819 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
2820 {"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},
2821 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
2822 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
2823 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
2824 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
2825 {"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},
2826 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
2827 {"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},
2828 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2829 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2830 {"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" },
2834 #define RTMP_PROTOCOL(flavor) \
2835 static const AVClass flavor##_class = { \
2836 .class_name = #flavor, \
2837 .item_name = av_default_item_name, \
2838 .option = rtmp_options, \
2839 .version = LIBAVUTIL_VERSION_INT, \
2842 URLProtocol ff_##flavor##_protocol = { \
2844 .url_open = rtmp_open, \
2845 .url_read = rtmp_read, \
2846 .url_read_seek = rtmp_seek, \
2847 .url_write = rtmp_write, \
2848 .url_close = rtmp_close, \
2849 .priv_data_size = sizeof(RTMPContext), \
2850 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2851 .priv_data_class= &flavor##_class, \
2856 RTMP_PROTOCOL(rtmpe)
2857 RTMP_PROTOCOL(rtmps)
2858 RTMP_PROTOCOL(rtmpt)
2859 RTMP_PROTOCOL(rtmpte)
2860 RTMP_PROTOCOL(rtmpts)