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 int has_audio; ///< presence of audio data
101 int has_video; ///< presence of video data
102 int received_metadata; ///< Indicates if we have received metadata about the streams
103 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
104 int flv_header_bytes; ///< number of initialized bytes in flv_header
105 int nb_invokes; ///< keeps track of invoke messages
106 char* tcurl; ///< url of the target stream
107 char* flashver; ///< version of the flash plugin
108 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
109 int swfhash_len; ///< length of the SHA256 hash
110 int swfsize; ///< size of the decompressed SWF file
111 char* swfurl; ///< url of the swf player
112 char* swfverify; ///< URL to player swf file, compute hash/size automatically
113 char swfverification[42]; ///< hash of the SWF verification
114 char* pageurl; ///< url of the web page
115 char* subscribe; ///< name of live stream to subscribe
116 int server_bw; ///< server bandwidth
117 int client_buffer_time; ///< client buffer time in ms
118 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
119 int encrypted; ///< use an encrypted connection (RTMPE only)
120 TrackedMethod*tracked_methods; ///< tracked methods buffer
121 int nb_tracked_methods; ///< number of tracked methods
122 int tracked_methods_size; ///< size of the tracked methods buffer
123 int listen; ///< listen mode flag
124 int listen_timeout; ///< listen timeout to wait for new connections
125 int nb_streamid; ///< The next stream id to return on createStream calls
126 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
129 char auth_params[500];
134 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
135 /** Client key used for digest signing */
136 static const uint8_t rtmp_player_key[] = {
137 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
138 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
140 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
141 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
142 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
145 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
146 /** Key used for RTMP server digest signing */
147 static const uint8_t rtmp_server_key[] = {
148 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
149 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
150 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
152 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
153 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
154 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
157 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
159 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
163 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
164 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
165 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
166 sizeof(*rt->tracked_methods))) < 0) {
167 rt->nb_tracked_methods = 0;
168 rt->tracked_methods_size = 0;
173 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
174 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
175 return AVERROR(ENOMEM);
176 rt->tracked_methods[rt->nb_tracked_methods].id = id;
177 rt->nb_tracked_methods++;
182 static void del_tracked_method(RTMPContext *rt, int index)
184 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
185 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
186 rt->nb_tracked_methods--;
189 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
190 char **tracked_method)
192 RTMPContext *rt = s->priv_data;
198 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
199 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
202 for (i = 0; i < rt->nb_tracked_methods; i++) {
203 if (rt->tracked_methods[i].id != pkt_id)
206 *tracked_method = rt->tracked_methods[i].name;
207 del_tracked_method(rt, i);
214 static void free_tracked_methods(RTMPContext *rt)
218 for (i = 0; i < rt->nb_tracked_methods; i ++)
219 av_free(rt->tracked_methods[i].name);
220 av_free(rt->tracked_methods);
221 rt->tracked_methods = NULL;
222 rt->tracked_methods_size = 0;
223 rt->nb_tracked_methods = 0;
226 static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
230 if (pkt->type == RTMP_PT_INVOKE && track) {
236 bytestream2_init(&gbc, pkt->data, pkt->size);
237 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
240 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
243 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
247 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
248 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
250 ff_rtmp_packet_destroy(pkt);
254 static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
259 /* The type must be B for Boolean, N for number, S for string, O for
260 * object, or Z for null. For Booleans the data must be either 0 or 1 for
261 * FALSE or TRUE, respectively. Likewise for Objects the data must be
262 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
263 * may be named, by prefixing the type with 'N' and specifying the name
264 * before the value (ie. NB:myFlag:1). This option may be used multiple times
265 * to construct arbitrary AMF sequences. */
266 if (param[0] && param[1] == ':') {
269 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
272 value = strchr(field, ':');
278 ff_amf_write_field_name(p, field);
285 ff_amf_write_bool(p, value[0] != '0');
288 ff_amf_write_string(p, value);
291 ff_amf_write_number(p, strtod(value, NULL));
294 ff_amf_write_null(p);
298 ff_amf_write_object_start(p);
300 ff_amf_write_object_end(p);
310 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
311 return AVERROR(EINVAL);
315 * Generate 'connect' call and send it to the server.
317 static int gen_connect(URLContext *s, RTMPContext *rt)
323 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
324 0, 4096 + APP_MAX_LENGTH)) < 0)
329 ff_amf_write_string(&p, "connect");
330 ff_amf_write_number(&p, ++rt->nb_invokes);
331 ff_amf_write_object_start(&p);
332 ff_amf_write_field_name(&p, "app");
333 ff_amf_write_string2(&p, rt->app, rt->auth_params);
336 ff_amf_write_field_name(&p, "type");
337 ff_amf_write_string(&p, "nonprivate");
339 ff_amf_write_field_name(&p, "flashVer");
340 ff_amf_write_string(&p, rt->flashver);
343 ff_amf_write_field_name(&p, "swfUrl");
344 ff_amf_write_string(&p, rt->swfurl);
347 ff_amf_write_field_name(&p, "tcUrl");
348 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
350 ff_amf_write_field_name(&p, "fpad");
351 ff_amf_write_bool(&p, 0);
352 ff_amf_write_field_name(&p, "capabilities");
353 ff_amf_write_number(&p, 15.0);
355 /* Tell the server we support all the audio codecs except
356 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
357 * which are unused in the RTMP protocol implementation. */
358 ff_amf_write_field_name(&p, "audioCodecs");
359 ff_amf_write_number(&p, 4071.0);
360 ff_amf_write_field_name(&p, "videoCodecs");
361 ff_amf_write_number(&p, 252.0);
362 ff_amf_write_field_name(&p, "videoFunction");
363 ff_amf_write_number(&p, 1.0);
366 ff_amf_write_field_name(&p, "pageUrl");
367 ff_amf_write_string(&p, rt->pageurl);
370 ff_amf_write_object_end(&p);
373 char *param = rt->conn;
375 // Write arbitrary AMF data to the Connect message.
378 param += strspn(param, " ");
381 sep = strchr(param, ' ');
384 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
385 // Invalid AMF parameter.
386 ff_rtmp_packet_destroy(&pkt);
397 pkt.size = p - pkt.data;
399 return rtmp_send_packet(rt, &pkt, 1);
402 static int read_connect(URLContext *s, RTMPContext *rt)
404 RTMPPacket pkt = { 0 };
414 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
415 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
418 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
419 if ((ret = handle_chunk_size(s, &pkt)) < 0)
422 ff_rtmp_packet_destroy(&pkt);
423 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
424 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
429 bytestream2_init(&gbc, cp, pkt.size);
430 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
431 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
432 ff_rtmp_packet_destroy(&pkt);
433 return AVERROR_INVALIDDATA;
435 if (strcmp(command, "connect")) {
436 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
437 ff_rtmp_packet_destroy(&pkt);
438 return AVERROR_INVALIDDATA;
440 ret = ff_amf_read_number(&gbc, &seqnum);
442 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
443 /* Here one could parse an AMF Object with data as flashVers and others. */
444 ret = ff_amf_get_field_value(gbc.buffer,
445 gbc.buffer + bytestream2_get_bytes_left(&gbc),
446 "app", tmpstr, sizeof(tmpstr));
448 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
449 if (!ret && strcmp(tmpstr, rt->app))
450 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
452 ff_rtmp_packet_destroy(&pkt);
454 // Send Window Acknowledgement Size (as defined in speficication)
455 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
456 RTMP_PT_SERVER_BW, 0, 4)) < 0)
459 bytestream_put_be32(&p, rt->server_bw);
460 pkt.size = p - pkt.data;
461 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
462 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
463 ff_rtmp_packet_destroy(&pkt);
466 // Send Peer Bandwidth
467 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
468 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
471 bytestream_put_be32(&p, rt->server_bw);
472 bytestream_put_byte(&p, 2); // dynamic
473 pkt.size = p - pkt.data;
474 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
475 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
476 ff_rtmp_packet_destroy(&pkt);
481 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
482 RTMP_PT_PING, 0, 6)) < 0)
486 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
487 bytestream_put_be32(&p, 0);
488 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
489 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
490 ff_rtmp_packet_destroy(&pkt);
495 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
496 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
500 bytestream_put_be32(&p, rt->out_chunk_size);
501 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
502 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
503 ff_rtmp_packet_destroy(&pkt);
507 // Send _result NetConnection.Connect.Success to connect
508 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
510 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
514 ff_amf_write_string(&p, "_result");
515 ff_amf_write_number(&p, seqnum);
517 ff_amf_write_object_start(&p);
518 ff_amf_write_field_name(&p, "fmsVer");
519 ff_amf_write_string(&p, "FMS/3,0,1,123");
520 ff_amf_write_field_name(&p, "capabilities");
521 ff_amf_write_number(&p, 31);
522 ff_amf_write_object_end(&p);
524 ff_amf_write_object_start(&p);
525 ff_amf_write_field_name(&p, "level");
526 ff_amf_write_string(&p, "status");
527 ff_amf_write_field_name(&p, "code");
528 ff_amf_write_string(&p, "NetConnection.Connect.Success");
529 ff_amf_write_field_name(&p, "description");
530 ff_amf_write_string(&p, "Connection succeeded.");
531 ff_amf_write_field_name(&p, "objectEncoding");
532 ff_amf_write_number(&p, 0);
533 ff_amf_write_object_end(&p);
535 pkt.size = p - pkt.data;
536 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
537 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
538 ff_rtmp_packet_destroy(&pkt);
542 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
543 RTMP_PT_INVOKE, 0, 30)) < 0)
546 ff_amf_write_string(&p, "onBWDone");
547 ff_amf_write_number(&p, 0);
548 ff_amf_write_null(&p);
549 ff_amf_write_number(&p, 8192);
550 pkt.size = p - pkt.data;
551 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
552 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
553 ff_rtmp_packet_destroy(&pkt);
559 * Generate 'releaseStream' call and send it to the server. It should make
560 * the server release some channel for media streams.
562 static int gen_release_stream(URLContext *s, RTMPContext *rt)
568 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
569 0, 29 + strlen(rt->playpath))) < 0)
572 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
574 ff_amf_write_string(&p, "releaseStream");
575 ff_amf_write_number(&p, ++rt->nb_invokes);
576 ff_amf_write_null(&p);
577 ff_amf_write_string(&p, rt->playpath);
579 return rtmp_send_packet(rt, &pkt, 1);
583 * Generate 'FCPublish' call and send it to the server. It should make
584 * the server preapare for receiving media streams.
586 static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
592 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
593 0, 25 + strlen(rt->playpath))) < 0)
596 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
598 ff_amf_write_string(&p, "FCPublish");
599 ff_amf_write_number(&p, ++rt->nb_invokes);
600 ff_amf_write_null(&p);
601 ff_amf_write_string(&p, rt->playpath);
603 return rtmp_send_packet(rt, &pkt, 1);
607 * Generate 'FCUnpublish' call and send it to the server. It should make
608 * the server destroy stream.
610 static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
616 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
617 0, 27 + strlen(rt->playpath))) < 0)
620 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
622 ff_amf_write_string(&p, "FCUnpublish");
623 ff_amf_write_number(&p, ++rt->nb_invokes);
624 ff_amf_write_null(&p);
625 ff_amf_write_string(&p, rt->playpath);
627 return rtmp_send_packet(rt, &pkt, 0);
631 * Generate 'createStream' call and send it to the server. It should make
632 * the server allocate some channel for media streams.
634 static int gen_create_stream(URLContext *s, RTMPContext *rt)
640 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
642 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
647 ff_amf_write_string(&p, "createStream");
648 ff_amf_write_number(&p, ++rt->nb_invokes);
649 ff_amf_write_null(&p);
651 return rtmp_send_packet(rt, &pkt, 1);
656 * Generate 'deleteStream' call and send it to the server. It should make
657 * the server remove some channel for media streams.
659 static int gen_delete_stream(URLContext *s, RTMPContext *rt)
665 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
667 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
672 ff_amf_write_string(&p, "deleteStream");
673 ff_amf_write_number(&p, ++rt->nb_invokes);
674 ff_amf_write_null(&p);
675 ff_amf_write_number(&p, rt->stream_id);
677 return rtmp_send_packet(rt, &pkt, 0);
681 * Generate 'getStreamLength' call and send it to the server. If the server
682 * knows the duration of the selected stream, it will reply with the duration
685 static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
691 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
692 0, 31 + strlen(rt->playpath))) < 0)
696 ff_amf_write_string(&p, "getStreamLength");
697 ff_amf_write_number(&p, ++rt->nb_invokes);
698 ff_amf_write_null(&p);
699 ff_amf_write_string(&p, rt->playpath);
701 return rtmp_send_packet(rt, &pkt, 1);
705 * Generate client buffer time and send it to the server.
707 static int gen_buffer_time(URLContext *s, RTMPContext *rt)
713 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
718 bytestream_put_be16(&p, 3);
719 bytestream_put_be32(&p, rt->stream_id);
720 bytestream_put_be32(&p, rt->client_buffer_time);
722 return rtmp_send_packet(rt, &pkt, 0);
726 * Generate 'play' call and send it to the server, then ping the server
727 * to start actual playing.
729 static int gen_play(URLContext *s, RTMPContext *rt)
735 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
737 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
738 0, 29 + strlen(rt->playpath))) < 0)
741 pkt.extra = rt->stream_id;
744 ff_amf_write_string(&p, "play");
745 ff_amf_write_number(&p, ++rt->nb_invokes);
746 ff_amf_write_null(&p);
747 ff_amf_write_string(&p, rt->playpath);
748 ff_amf_write_number(&p, rt->live * 1000);
750 return rtmp_send_packet(rt, &pkt, 1);
753 static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
759 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
762 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
765 pkt.extra = rt->stream_id;
768 ff_amf_write_string(&p, "seek");
769 ff_amf_write_number(&p, 0); //no tracking back responses
770 ff_amf_write_null(&p); //as usual, the first null param
771 ff_amf_write_number(&p, timestamp); //where we want to jump
773 return rtmp_send_packet(rt, &pkt, 1);
777 * Generate 'publish' call and send it to the server.
779 static int gen_publish(URLContext *s, RTMPContext *rt)
785 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
787 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
788 0, 30 + strlen(rt->playpath))) < 0)
791 pkt.extra = rt->stream_id;
794 ff_amf_write_string(&p, "publish");
795 ff_amf_write_number(&p, ++rt->nb_invokes);
796 ff_amf_write_null(&p);
797 ff_amf_write_string(&p, rt->playpath);
798 ff_amf_write_string(&p, "live");
800 return rtmp_send_packet(rt, &pkt, 1);
804 * Generate ping reply and send it to the server.
806 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
812 if (ppkt->size < 6) {
813 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
815 return AVERROR_INVALIDDATA;
818 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
819 ppkt->timestamp + 1, 6)) < 0)
823 bytestream_put_be16(&p, 7);
824 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
826 return rtmp_send_packet(rt, &pkt, 0);
830 * Generate SWF verification message and send it to the server.
832 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
838 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
839 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
844 bytestream_put_be16(&p, 27);
845 memcpy(p, rt->swfverification, 42);
847 return rtmp_send_packet(rt, &pkt, 0);
851 * Generate server bandwidth message and send it to the server.
853 static int gen_server_bw(URLContext *s, RTMPContext *rt)
859 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
864 bytestream_put_be32(&p, rt->server_bw);
866 return rtmp_send_packet(rt, &pkt, 0);
870 * Generate check bandwidth message and send it to the server.
872 static int gen_check_bw(URLContext *s, RTMPContext *rt)
878 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
883 ff_amf_write_string(&p, "_checkbw");
884 ff_amf_write_number(&p, ++rt->nb_invokes);
885 ff_amf_write_null(&p);
887 return rtmp_send_packet(rt, &pkt, 1);
891 * Generate report on bytes read so far and send it to the server.
893 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
899 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
904 bytestream_put_be32(&p, rt->bytes_read);
906 return rtmp_send_packet(rt, &pkt, 0);
909 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
910 const char *subscribe)
916 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
917 0, 27 + strlen(subscribe))) < 0)
921 ff_amf_write_string(&p, "FCSubscribe");
922 ff_amf_write_number(&p, ++rt->nb_invokes);
923 ff_amf_write_null(&p);
924 ff_amf_write_string(&p, subscribe);
926 return rtmp_send_packet(rt, &pkt, 1);
929 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
930 const uint8_t *key, int keylen, uint8_t *dst)
933 uint8_t hmac_buf[64+32] = {0};
936 sha = av_sha_alloc();
938 return AVERROR(ENOMEM);
941 memcpy(hmac_buf, key, keylen);
943 av_sha_init(sha, 256);
944 av_sha_update(sha,key, keylen);
945 av_sha_final(sha, hmac_buf);
947 for (i = 0; i < 64; i++)
948 hmac_buf[i] ^= HMAC_IPAD_VAL;
950 av_sha_init(sha, 256);
951 av_sha_update(sha, hmac_buf, 64);
953 av_sha_update(sha, src, len);
954 } else { //skip 32 bytes used for storing digest
955 av_sha_update(sha, src, gap);
956 av_sha_update(sha, src + gap + 32, len - gap - 32);
958 av_sha_final(sha, hmac_buf + 64);
960 for (i = 0; i < 64; i++)
961 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
962 av_sha_init(sha, 256);
963 av_sha_update(sha, hmac_buf, 64+32);
964 av_sha_final(sha, dst);
971 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
974 int i, digest_pos = 0;
976 for (i = 0; i < 4; i++)
977 digest_pos += buf[i + off];
978 digest_pos = digest_pos % mod_val + add_val;
984 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
985 * will be stored) into that packet.
987 * @param buf handshake data (1536 bytes)
988 * @param encrypted use an encrypted connection (RTMPE)
989 * @return offset to the digest inside input data
991 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
996 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
998 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1000 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1001 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1010 * Verify that the received server response has the expected digest value.
1012 * @param buf handshake data received from the server (1536 bytes)
1013 * @param off position to search digest offset from
1014 * @return 0 if digest is valid, digest position otherwise
1016 static int rtmp_validate_digest(uint8_t *buf, int off)
1019 int ret, digest_pos;
1021 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1023 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1024 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1029 if (!memcmp(digest, buf + digest_pos, 32))
1034 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1040 if (rt->swfhash_len != 32) {
1041 av_log(s, AV_LOG_ERROR,
1042 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1043 return AVERROR(EINVAL);
1046 p = &rt->swfverification[0];
1047 bytestream_put_byte(&p, 1);
1048 bytestream_put_byte(&p, 1);
1049 bytestream_put_be32(&p, rt->swfsize);
1050 bytestream_put_be32(&p, rt->swfsize);
1052 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1059 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1060 uint8_t **out_data, int64_t *out_size)
1062 z_stream zs = { 0 };
1067 zs.avail_in = in_size;
1068 zs.next_in = in_data;
1069 ret = inflateInit(&zs);
1071 return AVERROR_UNKNOWN;
1074 uint8_t tmp_buf[16384];
1076 zs.avail_out = sizeof(tmp_buf);
1077 zs.next_out = tmp_buf;
1079 ret = inflate(&zs, Z_NO_FLUSH);
1080 if (ret != Z_OK && ret != Z_STREAM_END) {
1081 ret = AVERROR_UNKNOWN;
1085 size = sizeof(tmp_buf) - zs.avail_out;
1086 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1087 ret = AVERROR(ENOMEM);
1092 memcpy(*out_data + *out_size, tmp_buf, size);
1094 } while (zs.avail_out == 0);
1102 static int rtmp_calc_swfhash(URLContext *s)
1104 RTMPContext *rt = s->priv_data;
1105 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1106 int64_t in_size, out_size;
1112 /* Get the SWF player file. */
1113 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1114 &s->interrupt_callback, NULL)) < 0) {
1115 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1119 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1124 if (!(in_data = av_malloc(in_size))) {
1125 ret = AVERROR(ENOMEM);
1129 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1133 ret = AVERROR_INVALIDDATA;
1137 if (!memcmp(in_data, "CWS", 3)) {
1138 /* Decompress the SWF player file using Zlib. */
1139 if (!(out_data = av_malloc(8))) {
1140 ret = AVERROR(ENOMEM);
1143 *in_data = 'F'; // magic stuff
1144 memcpy(out_data, in_data, 8);
1148 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1149 &out_data, &out_size)) < 0)
1152 av_log(s, AV_LOG_ERROR,
1153 "Zlib is required for decompressing the SWF player file.\n");
1154 ret = AVERROR(EINVAL);
1164 /* Compute the SHA256 hash of the SWF player file. */
1165 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1166 "Genuine Adobe Flash Player 001", 30,
1170 /* Set SWFVerification parameters. */
1171 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1172 rt->swfsize = swfsize;
1176 av_freep(&out_data);
1177 ffurl_close(stream);
1182 * Perform handshake with the server by means of exchanging pseudorandom data
1183 * signed with HMAC-SHA2 digest.
1185 * @return 0 if handshake succeeds, negative value otherwise
1187 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1190 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1191 3, // unencrypted data
1192 0, 0, 0, 0, // client uptime
1198 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1199 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1201 int server_pos, client_pos;
1202 uint8_t digest[32], signature[32];
1205 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1207 av_lfg_init(&rnd, 0xDEADC0DE);
1208 // generate handshake packet - 1536 bytes of pseudorandom data
1209 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1210 tosend[i] = av_lfg_get(&rnd) >> 24;
1212 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1213 /* When the client wants to use RTMPE, we have to change the command
1214 * byte to 0x06 which means to use encrypted data and we have to set
1215 * the flash version to at least 9.0.115.0. */
1222 /* Initialize the Diffie-Hellmann context and generate the public key
1223 * to send to the server. */
1224 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1228 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1232 if ((ret = ffurl_write(rt->stream, tosend,
1233 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1234 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1238 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1239 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1240 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1244 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1245 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1246 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1250 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1251 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1252 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1254 if (rt->is_input && serverdata[5] >= 3) {
1255 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1261 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1266 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1267 return AVERROR(EIO);
1271 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1272 * key are the last 32 bytes of the server handshake. */
1274 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1275 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1279 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1280 rtmp_server_key, sizeof(rtmp_server_key),
1285 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1286 0, digest, 32, signature);
1290 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1291 /* Compute the shared secret key sent by the server and initialize
1292 * the RC4 encryption. */
1293 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1294 tosend + 1, type)) < 0)
1297 /* Encrypt the signature received by the server. */
1298 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1301 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1302 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1303 return AVERROR(EIO);
1306 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1307 tosend[i] = av_lfg_get(&rnd) >> 24;
1308 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1309 rtmp_player_key, sizeof(rtmp_player_key),
1314 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1316 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1320 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1321 /* Encrypt the signature to be send to the server. */
1322 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1323 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1327 // write reply back to the server
1328 if ((ret = ffurl_write(rt->stream, tosend,
1329 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1332 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1333 /* Set RC4 keys for encryption and update the keystreams. */
1334 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1338 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1339 /* Compute the shared secret key sent by the server and initialize
1340 * the RC4 encryption. */
1341 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1342 tosend + 1, 1)) < 0)
1345 if (serverdata[0] == 9) {
1346 /* Encrypt the signature received by the server. */
1347 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1352 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1353 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1356 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1357 /* Set RC4 keys for encryption and update the keystreams. */
1358 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1366 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1367 uint32_t *second_int, char *arraydata,
1372 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1373 RTMP_HANDSHAKE_PACKET_SIZE);
1375 return AVERROR(EIO);
1376 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1377 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1378 " not following standard\n", (int)inoutsize);
1379 return AVERROR(EINVAL);
1382 *first_int = AV_RB32(arraydata);
1383 *second_int = AV_RB32(arraydata + 4);
1387 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1388 uint32_t second_int, char *arraydata, int size)
1392 AV_WB32(arraydata, first_int);
1393 AV_WB32(arraydata + 4, second_int);
1394 inoutsize = ffurl_write(rt->stream, arraydata,
1395 RTMP_HANDSHAKE_PACKET_SIZE);
1396 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1397 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1398 return AVERROR(EIO);
1405 * rtmp handshake server side
1407 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1409 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1411 uint32_t hs_my_epoch;
1412 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1413 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1420 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1421 if (inoutsize <= 0) {
1422 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1423 return AVERROR(EIO);
1426 if (buffer[0] != 3) {
1427 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1428 return AVERROR(EIO);
1430 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1431 av_log(s, AV_LOG_ERROR,
1432 "Unable to write answer - RTMP S0\n");
1433 return AVERROR(EIO);
1436 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1437 RTMP_HANDSHAKE_PACKET_SIZE);
1439 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1443 /* By now same epoch will be sent */
1444 hs_my_epoch = hs_epoch;
1445 /* Generate random */
1446 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1448 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1450 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1451 RTMP_HANDSHAKE_PACKET_SIZE);
1453 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1457 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1458 RTMP_HANDSHAKE_PACKET_SIZE);
1460 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1464 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1465 RTMP_HANDSHAKE_PACKET_SIZE);
1467 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1470 if (temp != hs_my_epoch)
1471 av_log(s, AV_LOG_WARNING,
1472 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1473 if (memcmp(buffer + 8, hs_s1 + 8,
1474 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1475 av_log(s, AV_LOG_WARNING,
1476 "Erroneous C2 Message random does not match up\n");
1481 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1483 RTMPContext *rt = s->priv_data;
1486 if (pkt->size < 4) {
1487 av_log(s, AV_LOG_ERROR,
1488 "Too short chunk size change packet (%d)\n",
1490 return AVERROR_INVALIDDATA;
1493 if (!rt->is_input) {
1494 /* Send the same chunk size change packet back to the server,
1495 * setting the outgoing chunk size to the same as the incoming one. */
1496 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1497 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1499 rt->out_chunk_size = AV_RB32(pkt->data);
1502 rt->in_chunk_size = AV_RB32(pkt->data);
1503 if (rt->in_chunk_size <= 0) {
1504 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1506 return AVERROR_INVALIDDATA;
1508 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1514 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1516 RTMPContext *rt = s->priv_data;
1519 if (pkt->size < 2) {
1520 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1522 return AVERROR_INVALIDDATA;
1525 t = AV_RB16(pkt->data);
1527 if ((ret = gen_pong(s, rt, pkt)) < 0)
1529 } else if (t == 26) {
1531 if ((ret = gen_swf_verification(s, rt)) < 0)
1534 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1541 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1543 RTMPContext *rt = s->priv_data;
1545 if (pkt->size < 4) {
1546 av_log(s, AV_LOG_ERROR,
1547 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1549 return AVERROR_INVALIDDATA;
1552 rt->client_report_size = AV_RB32(pkt->data);
1553 if (rt->client_report_size <= 0) {
1554 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1555 rt->client_report_size);
1556 return AVERROR_INVALIDDATA;
1559 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1560 rt->client_report_size >>= 1;
1565 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1567 RTMPContext *rt = s->priv_data;
1569 if (pkt->size < 4) {
1570 av_log(s, AV_LOG_ERROR,
1571 "Too short server bandwidth report packet (%d)\n",
1573 return AVERROR_INVALIDDATA;
1576 rt->server_bw = AV_RB32(pkt->data);
1577 if (rt->server_bw <= 0) {
1578 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1580 return AVERROR_INVALIDDATA;
1582 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1587 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1588 const char *opaque, const char *challenge)
1591 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1592 struct AVMD5 *md5 = av_md5_alloc();
1594 return AVERROR(ENOMEM);
1596 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1599 av_md5_update(md5, user, strlen(user));
1600 av_md5_update(md5, salt, strlen(salt));
1601 av_md5_update(md5, rt->password, strlen(rt->password));
1602 av_md5_final(md5, hash);
1603 av_base64_encode(hashstr, sizeof(hashstr), hash,
1606 av_md5_update(md5, hashstr, strlen(hashstr));
1608 av_md5_update(md5, opaque, strlen(opaque));
1610 av_md5_update(md5, challenge, strlen(challenge));
1611 av_md5_update(md5, challenge2, strlen(challenge2));
1612 av_md5_final(md5, hash);
1613 av_base64_encode(hashstr, sizeof(hashstr), hash,
1615 snprintf(rt->auth_params, sizeof(rt->auth_params),
1616 "?authmod=%s&user=%s&challenge=%s&response=%s",
1617 "adobe", user, challenge2, hashstr);
1619 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1620 "&opaque=%s", opaque);
1626 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1629 char hashstr1[33], hashstr2[33];
1630 const char *realm = "live";
1631 const char *method = "publish";
1632 const char *qop = "auth";
1633 const char *nc = "00000001";
1635 struct AVMD5 *md5 = av_md5_alloc();
1637 return AVERROR(ENOMEM);
1639 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1642 av_md5_update(md5, user, strlen(user));
1643 av_md5_update(md5, ":", 1);
1644 av_md5_update(md5, realm, strlen(realm));
1645 av_md5_update(md5, ":", 1);
1646 av_md5_update(md5, rt->password, strlen(rt->password));
1647 av_md5_final(md5, hash);
1648 ff_data_to_hex(hashstr1, hash, 16, 1);
1649 hashstr1[32] = '\0';
1652 av_md5_update(md5, method, strlen(method));
1653 av_md5_update(md5, ":/", 2);
1654 av_md5_update(md5, rt->app, strlen(rt->app));
1655 if (!strchr(rt->app, '/'))
1656 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1657 av_md5_final(md5, hash);
1658 ff_data_to_hex(hashstr2, hash, 16, 1);
1659 hashstr2[32] = '\0';
1662 av_md5_update(md5, hashstr1, strlen(hashstr1));
1663 av_md5_update(md5, ":", 1);
1665 av_md5_update(md5, nonce, strlen(nonce));
1666 av_md5_update(md5, ":", 1);
1667 av_md5_update(md5, nc, strlen(nc));
1668 av_md5_update(md5, ":", 1);
1669 av_md5_update(md5, cnonce, strlen(cnonce));
1670 av_md5_update(md5, ":", 1);
1671 av_md5_update(md5, qop, strlen(qop));
1672 av_md5_update(md5, ":", 1);
1673 av_md5_update(md5, hashstr2, strlen(hashstr2));
1674 av_md5_final(md5, hash);
1675 ff_data_to_hex(hashstr1, hash, 16, 1);
1677 snprintf(rt->auth_params, sizeof(rt->auth_params),
1678 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1679 "llnw", user, nonce, cnonce, nc, hashstr1);
1685 static int handle_connect_error(URLContext *s, const char *desc)
1687 RTMPContext *rt = s->priv_data;
1688 char buf[300], *ptr, authmod[15];
1690 const char *user = "", *salt = "", *opaque = NULL,
1691 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1693 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1694 !(cptr = strstr(desc, "authmod=llnw"))) {
1695 av_log(s, AV_LOG_ERROR,
1696 "Unknown connect error (unsupported authentication method?)\n");
1697 return AVERROR_UNKNOWN;
1699 cptr += strlen("authmod=");
1700 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1701 authmod[i++] = *cptr++;
1704 if (!rt->username[0] || !rt->password[0]) {
1705 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1706 return AVERROR_UNKNOWN;
1709 if (strstr(desc, "?reason=authfailed")) {
1710 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1711 return AVERROR_UNKNOWN;
1712 } else if (strstr(desc, "?reason=nosuchuser")) {
1713 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1714 return AVERROR_UNKNOWN;
1717 if (rt->auth_tried) {
1718 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1719 return AVERROR_UNKNOWN;
1722 rt->auth_params[0] = '\0';
1724 if (strstr(desc, "code=403 need auth")) {
1725 snprintf(rt->auth_params, sizeof(rt->auth_params),
1726 "?authmod=%s&user=%s", authmod, rt->username);
1730 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1731 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1732 return AVERROR_UNKNOWN;
1735 av_strlcpy(buf, cptr + 1, sizeof(buf));
1739 char *next = strchr(ptr, '&');
1740 char *value = strchr(ptr, '=');
1745 if (!strcmp(ptr, "user")) {
1747 } else if (!strcmp(ptr, "salt")) {
1749 } else if (!strcmp(ptr, "opaque")) {
1751 } else if (!strcmp(ptr, "challenge")) {
1753 } else if (!strcmp(ptr, "nonce")) {
1756 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1759 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1764 if (!strcmp(authmod, "adobe")) {
1765 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1768 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1776 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1778 RTMPContext *rt = s->priv_data;
1779 const uint8_t *data_end = pkt->data + pkt->size;
1780 char *tracked_method = NULL;
1781 int level = AV_LOG_ERROR;
1782 uint8_t tmpstr[256];
1785 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1788 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1789 "description", tmpstr, sizeof(tmpstr))) {
1790 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1791 !strcmp(tracked_method, "releaseStream") ||
1792 !strcmp(tracked_method, "FCSubscribe") ||
1793 !strcmp(tracked_method, "FCPublish"))) {
1794 /* Gracefully ignore Adobe-specific historical artifact errors. */
1795 level = AV_LOG_WARNING;
1797 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1798 ret = handle_connect_error(s, tmpstr);
1800 rt->do_reconnect = 1;
1801 level = AV_LOG_VERBOSE;
1804 ret = AVERROR_UNKNOWN;
1805 av_log(s, level, "Server error: %s\n", tmpstr);
1808 av_free(tracked_method);
1812 static int write_begin(URLContext *s)
1814 RTMPContext *rt = s->priv_data;
1816 RTMPPacket spkt = { 0 };
1819 // Send Stream Begin 1
1820 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1821 RTMP_PT_PING, 0, 6)) < 0) {
1822 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1826 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1827 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1828 bytestream2_put_be32(&pbc, rt->nb_streamid);
1830 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1831 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1833 ff_rtmp_packet_destroy(&spkt);
1838 static int write_status(URLContext *s, RTMPPacket *pkt,
1839 const char *status, const char *filename)
1841 RTMPContext *rt = s->priv_data;
1842 RTMPPacket spkt = { 0 };
1843 char statusmsg[128];
1847 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1849 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1850 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1855 spkt.extra = pkt->extra;
1856 ff_amf_write_string(&pp, "onStatus");
1857 ff_amf_write_number(&pp, 0);
1858 ff_amf_write_null(&pp);
1860 ff_amf_write_object_start(&pp);
1861 ff_amf_write_field_name(&pp, "level");
1862 ff_amf_write_string(&pp, "status");
1863 ff_amf_write_field_name(&pp, "code");
1864 ff_amf_write_string(&pp, status);
1865 ff_amf_write_field_name(&pp, "description");
1866 snprintf(statusmsg, sizeof(statusmsg),
1867 "%s is now published", filename);
1868 ff_amf_write_string(&pp, statusmsg);
1869 ff_amf_write_field_name(&pp, "details");
1870 ff_amf_write_string(&pp, filename);
1871 ff_amf_write_field_name(&pp, "clientid");
1872 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1873 ff_amf_write_string(&pp, statusmsg);
1874 ff_amf_write_object_end(&pp);
1876 spkt.size = pp - spkt.data;
1877 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1878 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1879 ff_rtmp_packet_destroy(&spkt);
1884 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1886 RTMPContext *rt = s->priv_data;
1892 const uint8_t *p = pkt->data;
1894 RTMPPacket spkt = { 0 };
1898 bytestream2_init(&gbc, p, pkt->size);
1899 if (ff_amf_read_string(&gbc, command, sizeof(command),
1901 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1902 return AVERROR_INVALIDDATA;
1905 ret = ff_amf_read_number(&gbc, &seqnum);
1908 ret = ff_amf_read_null(&gbc);
1911 if (!strcmp(command, "FCPublish") ||
1912 !strcmp(command, "publish")) {
1913 ret = ff_amf_read_string(&gbc, filename,
1914 sizeof(filename), &stringlen);
1917 pchar = strrchr(s->filename, '/');
1919 av_log(s, AV_LOG_WARNING,
1920 "Unable to find / in url %s, bad format\n",
1922 pchar = s->filename;
1925 if (strcmp(pchar, filename))
1926 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1927 " %s\n", filename, pchar);
1929 rt->state = STATE_RECEIVING;
1932 if (!strcmp(command, "FCPublish")) {
1933 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1935 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1936 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1940 ff_amf_write_string(&pp, "onFCPublish");
1941 } else if (!strcmp(command, "publish")) {
1942 ret = write_begin(s);
1946 // Send onStatus(NetStream.Publish.Start)
1947 return write_status(s, pkt, "NetStream.Publish.Start",
1949 } else if (!strcmp(command, "play")) {
1950 ret = write_begin(s);
1953 rt->state = STATE_SENDING;
1954 return write_status(s, pkt, "NetStream.Play.Start",
1957 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1959 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1960 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1964 ff_amf_write_string(&pp, "_result");
1965 ff_amf_write_number(&pp, seqnum);
1966 ff_amf_write_null(&pp);
1967 if (!strcmp(command, "createStream")) {
1969 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1970 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1971 ff_amf_write_number(&pp, rt->nb_streamid);
1972 /* By now we don't control which streams are removed in
1973 * deleteStream. There is no stream creation control
1974 * if a client creates more than 2^32 - 2 streams. */
1977 spkt.size = pp - spkt.data;
1978 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1979 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1980 ff_rtmp_packet_destroy(&spkt);
1985 * Read the AMF_NUMBER response ("_result") to a function call
1986 * (e.g. createStream()). This response should be made up of the AMF_STRING
1987 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
1988 * successful response, we will return set the value to number (otherwise number
1989 * will not be changed).
1991 * @return 0 if reading the value succeeds, negative value otherwiss
1993 static int read_number_result(RTMPPacket *pkt, double *number)
1995 // We only need to fit "_result" in this.
1996 uint8_t strbuffer[8];
2001 bytestream2_init(&gbc, pkt->data, pkt->size);
2003 // Value 1/4: "_result" as AMF_STRING
2004 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2005 return AVERROR_INVALIDDATA;
2006 if (strcmp(strbuffer, "_result"))
2007 return AVERROR_INVALIDDATA;
2008 // Value 2/4: The callee reference number
2009 if (ff_amf_read_number(&gbc, &numbuffer))
2010 return AVERROR_INVALIDDATA;
2012 if (ff_amf_read_null(&gbc))
2013 return AVERROR_INVALIDDATA;
2014 // Value 4/4: The resonse as AMF_NUMBER
2015 if (ff_amf_read_number(&gbc, &numbuffer))
2016 return AVERROR_INVALIDDATA;
2018 *number = numbuffer;
2023 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2025 RTMPContext *rt = s->priv_data;
2026 char *tracked_method = NULL;
2029 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2032 if (!tracked_method) {
2033 /* Ignore this reply when the current method is not tracked. */
2037 if (!strcmp(tracked_method, "connect")) {
2038 if (!rt->is_input) {
2039 if ((ret = gen_release_stream(s, rt)) < 0)
2042 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2045 if ((ret = gen_server_bw(s, rt)) < 0)
2049 if ((ret = gen_create_stream(s, rt)) < 0)
2053 /* Send the FCSubscribe command when the name of live
2054 * stream is defined by the user or if it's a live stream. */
2055 if (rt->subscribe) {
2056 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2058 } else if (rt->live == -1) {
2059 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2063 } else if (!strcmp(tracked_method, "createStream")) {
2065 if (read_number_result(pkt, &stream_id)) {
2066 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2068 rt->stream_id = stream_id;
2071 if (!rt->is_input) {
2072 if ((ret = gen_publish(s, rt)) < 0)
2075 if (rt->live != -1) {
2076 if ((ret = gen_get_stream_length(s, rt)) < 0)
2079 if ((ret = gen_play(s, rt)) < 0)
2081 if ((ret = gen_buffer_time(s, rt)) < 0)
2084 } else if (!strcmp(tracked_method, "getStreamLength")) {
2085 if (read_number_result(pkt, &rt->duration)) {
2086 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2091 av_free(tracked_method);
2095 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2097 RTMPContext *rt = s->priv_data;
2098 const uint8_t *data_end = pkt->data + pkt->size;
2099 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2100 uint8_t tmpstr[256];
2103 for (i = 0; i < 2; i++) {
2104 t = ff_amf_tag_size(ptr, data_end);
2110 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2111 if (!t && !strcmp(tmpstr, "error")) {
2112 t = ff_amf_get_field_value(ptr, data_end,
2113 "description", tmpstr, sizeof(tmpstr));
2114 if (t || !tmpstr[0])
2115 t = ff_amf_get_field_value(ptr, data_end, "code",
2116 tmpstr, sizeof(tmpstr));
2118 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2122 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2123 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2124 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2125 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2126 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2127 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2132 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2134 RTMPContext *rt = s->priv_data;
2137 //TODO: check for the messages sent for wrong state?
2138 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2139 if ((ret = handle_invoke_error(s, pkt)) < 0)
2141 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2142 if ((ret = handle_invoke_result(s, pkt)) < 0)
2144 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2145 if ((ret = handle_invoke_status(s, pkt)) < 0)
2147 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2148 if ((ret = gen_check_bw(s, rt)) < 0)
2150 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2151 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2152 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2153 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2154 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2155 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2156 if ((ret = send_invoke_response(s, pkt)) < 0)
2163 static int update_offset(RTMPContext *rt, int size)
2167 // generate packet header and put data into buffer for FLV demuxer
2168 if (rt->flv_off < rt->flv_size) {
2169 // There is old unread data in the buffer, thus append at the end
2170 old_flv_size = rt->flv_size;
2171 rt->flv_size += size;
2173 // All data has been read, write the new data at the start of the buffer
2175 rt->flv_size = size;
2179 return old_flv_size;
2182 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2184 int old_flv_size, ret;
2186 const uint8_t *data = pkt->data + skip;
2187 const int size = pkt->size - skip;
2188 uint32_t ts = pkt->timestamp;
2190 if (pkt->type == RTMP_PT_AUDIO) {
2192 } else if (pkt->type == RTMP_PT_VIDEO) {
2196 old_flv_size = update_offset(rt, size + 15);
2198 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2199 rt->flv_size = rt->flv_off = 0;
2202 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2203 bytestream2_skip_p(&pbc, old_flv_size);
2204 bytestream2_put_byte(&pbc, pkt->type);
2205 bytestream2_put_be24(&pbc, size);
2206 bytestream2_put_be24(&pbc, ts);
2207 bytestream2_put_byte(&pbc, ts >> 24);
2208 bytestream2_put_be24(&pbc, 0);
2209 bytestream2_put_buffer(&pbc, data, size);
2210 bytestream2_put_be32(&pbc, 0);
2215 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2217 RTMPContext *rt = s->priv_data;
2218 uint8_t commandbuffer[64];
2219 char statusmsg[128];
2220 int stringlen, ret, skip = 0;
2223 bytestream2_init(&gbc, pkt->data, pkt->size);
2224 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2226 return AVERROR_INVALIDDATA;
2228 if (!strcmp(commandbuffer, "onMetaData")) {
2229 // metadata properties should be stored in a mixed array
2230 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2231 // We have found a metaData Array so flv can determine the streams
2233 rt->received_metadata = 1;
2234 // skip 32-bit max array index
2235 bytestream2_skip(&gbc, 4);
2236 while (bytestream2_get_bytes_left(&gbc) > 3) {
2237 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2239 return AVERROR_INVALIDDATA;
2240 // We do not care about the content of the property (yet).
2241 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2243 return AVERROR_INVALIDDATA;
2244 bytestream2_skip(&gbc, stringlen);
2246 // The presence of the following properties indicates that the
2247 // respective streams are present.
2248 if (!strcmp(statusmsg, "videocodecid")) {
2251 if (!strcmp(statusmsg, "audiocodecid")) {
2255 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2256 return AVERROR_INVALIDDATA;
2260 // Skip the @setDataFrame string and validate it is a notification
2261 if (!strcmp(commandbuffer, "@setDataFrame")) {
2262 skip = gbc.buffer - pkt->data;
2263 ret = ff_amf_read_string(&gbc, statusmsg,
2264 sizeof(statusmsg), &stringlen);
2266 return AVERROR_INVALIDDATA;
2269 return append_flv_data(rt, pkt, skip);
2273 * Parse received packet and possibly perform some action depending on
2274 * the packet contents.
2275 * @return 0 for no errors, negative values for serious errors which prevent
2276 * further communications, positive values for uncritical errors
2278 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2283 ff_rtmp_packet_dump(s, pkt);
2286 switch (pkt->type) {
2287 case RTMP_PT_BYTES_READ:
2288 av_dlog(s, "received bytes read report\n");
2290 case RTMP_PT_CHUNK_SIZE:
2291 if ((ret = handle_chunk_size(s, pkt)) < 0)
2295 if ((ret = handle_ping(s, pkt)) < 0)
2298 case RTMP_PT_CLIENT_BW:
2299 if ((ret = handle_client_bw(s, pkt)) < 0)
2302 case RTMP_PT_SERVER_BW:
2303 if ((ret = handle_server_bw(s, pkt)) < 0)
2306 case RTMP_PT_INVOKE:
2307 if ((ret = handle_invoke(s, pkt)) < 0)
2312 case RTMP_PT_METADATA:
2313 case RTMP_PT_NOTIFY:
2314 /* Audio, Video and Metadata packets are parsed in get_packet() */
2317 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2323 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2325 int ret, old_flv_size, type;
2326 const uint8_t *next;
2329 uint32_t ts, cts, pts = 0;
2331 old_flv_size = update_offset(rt, pkt->size);
2333 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2334 rt->flv_size = rt->flv_off = 0;
2339 p = rt->flv_data + old_flv_size;
2341 /* copy data while rewriting timestamps */
2342 ts = pkt->timestamp;
2344 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2345 type = bytestream_get_byte(&next);
2346 size = bytestream_get_be24(&next);
2347 cts = bytestream_get_be24(&next);
2348 cts |= bytestream_get_byte(&next) << 24;
2353 if (size + 3 + 4 > pkt->data + pkt->size - next)
2355 bytestream_put_byte(&p, type);
2356 bytestream_put_be24(&p, size);
2357 bytestream_put_be24(&p, ts);
2358 bytestream_put_byte(&p, ts >> 24);
2359 memcpy(p, next, size + 3 + 4);
2360 next += size + 3 + 4;
2363 if (p != rt->flv_data + rt->flv_size) {
2364 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2365 "RTMP_PT_METADATA packet\n");
2366 rt->flv_size = p - rt->flv_data;
2373 * Interact with the server by receiving and sending RTMP packets until
2374 * there is some significant data (media data or expected status notification).
2376 * @param s reading context
2377 * @param for_header non-zero value tells function to work until it
2378 * gets notification from the server that playing has been started,
2379 * otherwise function will work until some media data is received (or
2381 * @return 0 for successful operation, negative value in case of error
2383 static int get_packet(URLContext *s, int for_header)
2385 RTMPContext *rt = s->priv_data;
2388 if (rt->state == STATE_STOPPED)
2392 RTMPPacket rpkt = { 0 };
2393 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2394 rt->in_chunk_size, &rt->prev_pkt[0],
2395 &rt->nb_prev_pkt[0])) <= 0) {
2397 return AVERROR(EAGAIN);
2399 return AVERROR(EIO);
2402 rt->bytes_read += ret;
2403 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2404 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2405 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2407 rt->last_bytes_read = rt->bytes_read;
2410 ret = rtmp_parse_result(s, rt, &rpkt);
2412 // At this point we must check if we are in the seek state and continue
2413 // with the next packet. handle_invoke will get us out of this state
2414 // when the right message is encountered
2415 if (rt->state == STATE_SEEKING) {
2416 ff_rtmp_packet_destroy(&rpkt);
2417 // We continue, let the natural flow of things happen:
2418 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2422 if (ret < 0) {//serious error in current packet
2423 ff_rtmp_packet_destroy(&rpkt);
2426 if (rt->do_reconnect && for_header) {
2427 ff_rtmp_packet_destroy(&rpkt);
2430 if (rt->state == STATE_STOPPED) {
2431 ff_rtmp_packet_destroy(&rpkt);
2434 if (for_header && (rt->state == STATE_PLAYING ||
2435 rt->state == STATE_PUBLISHING ||
2436 rt->state == STATE_SENDING ||
2437 rt->state == STATE_RECEIVING)) {
2438 ff_rtmp_packet_destroy(&rpkt);
2441 if (!rpkt.size || !rt->is_input) {
2442 ff_rtmp_packet_destroy(&rpkt);
2445 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2446 ret = append_flv_data(rt, &rpkt, 0);
2447 ff_rtmp_packet_destroy(&rpkt);
2449 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2450 ret = handle_notify(s, &rpkt);
2451 ff_rtmp_packet_destroy(&rpkt);
2453 } else if (rpkt.type == RTMP_PT_METADATA) {
2454 ret = handle_metadata(rt, &rpkt);
2455 ff_rtmp_packet_destroy(&rpkt);
2458 ff_rtmp_packet_destroy(&rpkt);
2462 static int rtmp_close(URLContext *h)
2464 RTMPContext *rt = h->priv_data;
2467 if (!rt->is_input) {
2468 rt->flv_data = NULL;
2469 if (rt->out_pkt.size)
2470 ff_rtmp_packet_destroy(&rt->out_pkt);
2471 if (rt->state > STATE_FCPUBLISH)
2472 ret = gen_fcunpublish_stream(h, rt);
2474 if (rt->state > STATE_HANDSHAKED)
2475 ret = gen_delete_stream(h, rt);
2476 for (i = 0; i < 2; i++) {
2477 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2478 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2479 av_freep(&rt->prev_pkt[i]);
2482 free_tracked_methods(rt);
2483 av_freep(&rt->flv_data);
2484 ffurl_close(rt->stream);
2489 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2490 * demuxer about the duration of the stream.
2492 * This should only be done if there was no real onMetadata packet sent by the
2493 * server at the start of the stream and if we were able to retrieve a valid
2494 * duration via a getStreamLength call.
2496 * @return 0 for successful operation, negative value in case of error
2498 static int inject_fake_duration_metadata(RTMPContext *rt)
2500 // We need to insert the metdata packet directly after the FLV
2501 // header, i.e. we need to move all other already read data by the
2502 // size of our fake metadata packet.
2505 // Keep old flv_data pointer
2506 uint8_t* old_flv_data = rt->flv_data;
2507 // Allocate a new flv_data pointer with enough space for the additional package
2508 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2509 rt->flv_data = old_flv_data;
2510 return AVERROR(ENOMEM);
2514 memcpy(rt->flv_data, old_flv_data, 13);
2515 // Copy remaining packets
2516 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2517 // Increase the size by the injected packet
2519 // Delete the old FLV data
2520 av_free(old_flv_data);
2522 p = rt->flv_data + 13;
2523 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2524 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2525 bytestream_put_be24(&p, 0); // timestamp
2526 bytestream_put_be32(&p, 0); // reserved
2528 // first event name as a string
2529 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2530 // "onMetaData" as AMF string
2531 bytestream_put_be16(&p, 10);
2532 bytestream_put_buffer(&p, "onMetaData", 10);
2534 // mixed array (hash) with size and string/type/data tuples
2535 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2536 bytestream_put_be32(&p, 1); // metadata_count
2538 // "duration" as AMF string
2539 bytestream_put_be16(&p, 8);
2540 bytestream_put_buffer(&p, "duration", 8);
2541 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2542 bytestream_put_be64(&p, av_double2int(rt->duration));
2545 bytestream_put_be16(&p, 0); // Empty string
2546 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2547 bytestream_put_be32(&p, 40); // size of data part (sum of all parts below)
2553 * Open RTMP connection and verify that the stream can be played.
2555 * URL syntax: rtmp://server[:port][/app][/playpath]
2556 * where 'app' is first one or two directories in the path
2557 * (e.g. /ondemand/, /flash/live/, etc.)
2558 * and 'playpath' is a file name (the rest of the path,
2559 * may be prefixed with "mp4:")
2561 static int rtmp_open(URLContext *s, const char *uri, int flags)
2563 RTMPContext *rt = s->priv_data;
2564 char proto[8], hostname[256], path[1024], auth[100], *fname;
2565 char *old_app, *qmark, fname_buffer[1024];
2568 AVDictionary *opts = NULL;
2571 if (rt->listen_timeout > 0)
2574 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2576 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2577 hostname, sizeof(hostname), &port,
2578 path, sizeof(path), s->filename);
2580 if (strchr(path, ' ')) {
2581 av_log(s, AV_LOG_WARNING,
2582 "Detected librtmp style URL parameters, these aren't supported "
2583 "by the libavformat internal RTMP handler currently enabled. "
2584 "See the documentation for the correct way to pass parameters.\n");
2588 char *ptr = strchr(auth, ':');
2591 av_strlcpy(rt->username, auth, sizeof(rt->username));
2592 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2596 if (rt->listen && strcmp(proto, "rtmp")) {
2597 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2599 return AVERROR(EINVAL);
2601 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2602 if (!strcmp(proto, "rtmpts"))
2603 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2605 /* open the http tunneling connection */
2606 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2607 } else if (!strcmp(proto, "rtmps")) {
2608 /* open the tls connection */
2610 port = RTMPS_DEFAULT_PORT;
2611 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2612 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2613 if (!strcmp(proto, "rtmpte"))
2614 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2616 /* open the encrypted connection */
2617 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2620 /* open the tcp connection */
2622 port = RTMP_DEFAULT_PORT;
2624 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2625 "?listen&listen_timeout=%d",
2626 rt->listen_timeout * 1000);
2628 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2632 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2633 &s->interrupt_callback, &opts)) < 0) {
2634 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2638 if (rt->swfverify) {
2639 if ((ret = rtmp_calc_swfhash(s)) < 0)
2643 rt->state = STATE_START;
2644 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2646 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2649 rt->out_chunk_size = 128;
2650 rt->in_chunk_size = 128; // Probably overwritten later
2651 rt->state = STATE_HANDSHAKED;
2653 // Keep the application name when it has been defined by the user.
2656 rt->app = av_malloc(APP_MAX_LENGTH);
2658 ret = AVERROR(ENOMEM);
2662 //extract "app" part from path
2663 qmark = strchr(path, '?');
2664 if (qmark && strstr(qmark, "slist=")) {
2666 // After slist we have the playpath, before the params, the app
2667 av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH));
2668 fname = strstr(path, "slist=") + 6;
2669 // Strip any further query parameters from fname
2670 amp = strchr(fname, '&');
2672 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2673 sizeof(fname_buffer)));
2674 fname = fname_buffer;
2676 } else if (!strncmp(path, "/ondemand/", 10)) {
2678 memcpy(rt->app, "ondemand", 9);
2680 char *next = *path ? path + 1 : path;
2681 char *p = strchr(next, '/');
2686 // make sure we do not mismatch a playpath for an application instance
2687 char *c = strchr(p + 1, ':');
2688 fname = strchr(p + 1, '/');
2689 if (!fname || (c && c < fname)) {
2691 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2694 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2700 // The name of application has been defined by the user, override it.
2701 if (strlen(old_app) >= APP_MAX_LENGTH) {
2702 ret = AVERROR(EINVAL);
2709 if (!rt->playpath) {
2710 int len = strlen(fname);
2712 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2713 if (!rt->playpath) {
2714 ret = AVERROR(ENOMEM);
2718 if (!strchr(fname, ':') && len >= 4 &&
2719 (!strcmp(fname + len - 4, ".f4v") ||
2720 !strcmp(fname + len - 4, ".mp4"))) {
2721 memcpy(rt->playpath, "mp4:", 5);
2723 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2724 fname[len - 4] = '\0';
2725 rt->playpath[0] = 0;
2727 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2731 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2733 ret = AVERROR(ENOMEM);
2736 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2737 port, "/%s", rt->app);
2740 if (!rt->flashver) {
2741 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2742 if (!rt->flashver) {
2743 ret = AVERROR(ENOMEM);
2747 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2748 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2749 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2751 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2752 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2756 rt->client_report_size = 1048576;
2760 rt->received_metadata = 0;
2761 rt->last_bytes_read = 0;
2762 rt->server_bw = 2500000;
2765 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2766 proto, path, rt->app, rt->playpath);
2768 if ((ret = gen_connect(s, rt)) < 0)
2771 if ((ret = read_connect(s, s->priv_data)) < 0)
2776 ret = get_packet(s, 1);
2777 } while (ret == AVERROR(EAGAIN));
2781 if (rt->do_reconnect) {
2783 ffurl_close(rt->stream);
2785 rt->do_reconnect = 0;
2787 for (i = 0; i < 2; i++)
2788 memset(rt->prev_pkt[i], 0,
2789 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2790 free_tracked_methods(rt);
2796 // generate FLV header for demuxer
2798 if ((err = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2801 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2803 // Read packets until we reach the first A/V packet or read metadata.
2804 // If there was a metadata package in front of the A/V packets, we can
2805 // build the FLV header from this. If we do not receive any metadata,
2806 // the FLV decoder will allocate the needed streams when their first
2807 // audio or video packet arrives.
2808 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2809 if ((ret = get_packet(s, 0)) < 0)
2813 // Either after we have read the metadata or (if there is none) the
2814 // first packet of an A/V stream, we have a better knowledge about the
2815 // streams, so set the FLV header accordingly.
2816 if (rt->has_audio) {
2817 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2819 if (rt->has_video) {
2820 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2823 // If we received the first packet of an A/V stream and no metadata but
2824 // the server returned a valid duration, create a fake metadata packet
2825 // to inform the FLV decoder about the duration.
2826 if (!rt->received_metadata && rt->duration > 0) {
2827 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2832 rt->flv_data = NULL;
2834 rt->skip_bytes = 13;
2837 s->max_packet_size = rt->stream->max_packet_size;
2842 av_dict_free(&opts);
2847 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2849 RTMPContext *rt = s->priv_data;
2850 int orig_size = size;
2854 int data_left = rt->flv_size - rt->flv_off;
2856 if (data_left >= size) {
2857 memcpy(buf, rt->flv_data + rt->flv_off, size);
2858 rt->flv_off += size;
2861 if (data_left > 0) {
2862 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2865 rt->flv_off = rt->flv_size;
2868 if ((ret = get_packet(s, 0)) < 0)
2874 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2877 RTMPContext *rt = s->priv_data;
2879 av_log(s, AV_LOG_DEBUG,
2880 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2881 stream_index, timestamp, flags);
2882 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2883 av_log(s, AV_LOG_ERROR,
2884 "Unable to send seek command on stream index %d at timestamp "
2885 "%"PRId64" with flags %08x\n",
2886 stream_index, timestamp, flags);
2889 rt->flv_off = rt->flv_size;
2890 rt->state = STATE_SEEKING;
2894 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2896 RTMPContext *rt = s->priv_data;
2897 int size_temp = size;
2898 int pktsize, pkttype;
2900 const uint8_t *buf_temp = buf;
2905 if (rt->skip_bytes) {
2906 int skip = FFMIN(rt->skip_bytes, size_temp);
2909 rt->skip_bytes -= skip;
2913 if (rt->flv_header_bytes < RTMP_HEADER) {
2914 const uint8_t *header = rt->flv_header;
2915 int copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2916 int channel = RTMP_AUDIO_CHANNEL;
2917 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2918 rt->flv_header_bytes += copy;
2920 if (rt->flv_header_bytes < RTMP_HEADER)
2923 pkttype = bytestream_get_byte(&header);
2924 pktsize = bytestream_get_be24(&header);
2925 ts = bytestream_get_be24(&header);
2926 ts |= bytestream_get_byte(&header) << 24;
2927 bytestream_get_be24(&header);
2928 rt->flv_size = pktsize;
2930 if (pkttype == RTMP_PT_VIDEO)
2931 channel = RTMP_VIDEO_CHANNEL;
2933 //force 12bytes header
2934 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2935 pkttype == RTMP_PT_NOTIFY) {
2936 if (pkttype == RTMP_PT_NOTIFY)
2938 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2939 &rt->nb_prev_pkt[1],
2942 rt->prev_pkt[1][channel].channel_id = 0;
2945 //this can be a big packet, it's better to send it right here
2946 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2947 pkttype, ts, pktsize)) < 0)
2950 rt->out_pkt.extra = rt->stream_id;
2951 rt->flv_data = rt->out_pkt.data;
2953 if (pkttype == RTMP_PT_NOTIFY)
2954 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
2957 if (rt->flv_size - rt->flv_off > size_temp) {
2958 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
2959 rt->flv_off += size_temp;
2962 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
2963 size_temp -= rt->flv_size - rt->flv_off;
2964 rt->flv_off += rt->flv_size - rt->flv_off;
2967 if (rt->flv_off == rt->flv_size) {
2970 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
2974 rt->flv_header_bytes = 0;
2975 rt->flv_nb_packets++;
2977 } while (buf_temp - buf < size);
2979 if (rt->flv_nb_packets < rt->flush_interval)
2981 rt->flv_nb_packets = 0;
2983 /* set stream into nonblocking mode */
2984 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
2986 /* try to read one byte from the stream */
2987 ret = ffurl_read(rt->stream, &c, 1);
2989 /* switch the stream back into blocking mode */
2990 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
2992 if (ret == AVERROR(EAGAIN)) {
2993 /* no incoming data to handle */
2995 } else if (ret < 0) {
2997 } else if (ret == 1) {
2998 RTMPPacket rpkt = { 0 };
3000 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3003 &rt->nb_prev_pkt[0], c)) <= 0)
3006 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3009 ff_rtmp_packet_destroy(&rpkt);
3015 #define OFFSET(x) offsetof(RTMPContext, x)
3016 #define DEC AV_OPT_FLAG_DECODING_PARAM
3017 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3019 static const AVOption rtmp_options[] = {
3020 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3021 {"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},
3022 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3023 {"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},
3024 {"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},
3025 {"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"},
3026 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3027 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3028 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3029 {"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},
3030 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3031 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3032 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3033 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3034 {"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},
3035 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3036 {"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},
3037 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3038 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3039 {"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" },
3043 #define RTMP_PROTOCOL(flavor) \
3044 static const AVClass flavor##_class = { \
3045 .class_name = #flavor, \
3046 .item_name = av_default_item_name, \
3047 .option = rtmp_options, \
3048 .version = LIBAVUTIL_VERSION_INT, \
3051 URLProtocol ff_##flavor##_protocol = { \
3053 .url_open = rtmp_open, \
3054 .url_read = rtmp_read, \
3055 .url_read_seek = rtmp_seek, \
3056 .url_write = rtmp_write, \
3057 .url_close = rtmp_close, \
3058 .priv_data_size = sizeof(RTMPContext), \
3059 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3060 .priv_data_class= &flavor##_class, \
3065 RTMP_PROTOCOL(rtmpe)
3066 RTMP_PROTOCOL(rtmps)
3067 RTMP_PROTOCOL(rtmpt)
3068 RTMP_PROTOCOL(rtmpte)
3069 RTMP_PROTOCOL(rtmpts)