2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavcodec/bytestream.h"
28 #include "libavutil/avstring.h"
29 #include "libavutil/base64.h"
30 #include "libavutil/intfloat.h"
31 #include "libavutil/lfg.h"
32 #include "libavutil/md5.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/random_seed.h"
35 #include "libavutil/sha.h"
43 #include "rtmpcrypt.h"
51 #define APP_MAX_LENGTH 1024
52 #define PLAYPATH_MAX_LENGTH 256
53 #define TCURL_MAX_LENGTH 512
54 #define FLASHVER_MAX_LENGTH 64
55 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
56 #define RTMP_HEADER 11
58 /** RTMP protocol handler state */
60 STATE_START, ///< client has not done anything yet
61 STATE_HANDSHAKED, ///< client has performed handshake
62 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
63 STATE_PLAYING, ///< client has started receiving multimedia data from server
64 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
65 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
66 STATE_RECEIVING, ///< received a publish command (for input)
67 STATE_SENDING, ///< received a play command (for output)
68 STATE_STOPPED, ///< the broadcast has been stopped
71 typedef struct TrackedMethod {
76 /** protocol handler context */
77 typedef struct RTMPContext {
79 URLContext* stream; ///< TCP stream used in interactions with RTMP server
80 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
81 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
82 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
83 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
84 int is_input; ///< input/output flag
85 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
86 int live; ///< 0: recorded, -1: live, -2: both
87 char *app; ///< name of application
88 char *conn; ///< append arbitrary AMF data to the Connect message
89 ClientState state; ///< current state
90 int stream_id; ///< ID assigned by the server for the stream
91 uint8_t* flv_data; ///< buffer with data for demuxer
92 int flv_size; ///< current buffer size
93 int flv_off; ///< number of bytes read from current buffer
94 int flv_nb_packets; ///< number of flv packets published
95 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
96 uint32_t client_report_size; ///< number of bytes after which client should report to server
97 uint32_t bytes_read; ///< number of bytes read from server
98 uint32_t last_bytes_read; ///< number of bytes read last reported to server
99 uint32_t last_timestamp; ///< last timestamp received in a packet
100 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
101 int has_audio; ///< presence of audio data
102 int has_video; ///< presence of video data
103 int received_metadata; ///< Indicates if we have received metadata about the streams
104 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
105 int flv_header_bytes; ///< number of initialized bytes in flv_header
106 int nb_invokes; ///< keeps track of invoke messages
107 char* tcurl; ///< url of the target stream
108 char* flashver; ///< version of the flash plugin
109 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
110 int swfhash_len; ///< length of the SHA256 hash
111 int swfsize; ///< size of the decompressed SWF file
112 char* swfurl; ///< url of the swf player
113 char* swfverify; ///< URL to player swf file, compute hash/size automatically
114 char swfverification[42]; ///< hash of the SWF verification
115 char* pageurl; ///< url of the web page
116 char* subscribe; ///< name of live stream to subscribe
117 int server_bw; ///< server bandwidth
118 int client_buffer_time; ///< client buffer time in ms
119 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
120 int encrypted; ///< use an encrypted connection (RTMPE only)
121 TrackedMethod*tracked_methods; ///< tracked methods buffer
122 int nb_tracked_methods; ///< number of tracked methods
123 int tracked_methods_size; ///< size of the tracked methods buffer
124 int listen; ///< listen mode flag
125 int listen_timeout; ///< listen timeout to wait for new connections
126 int nb_streamid; ///< The next stream id to return on createStream calls
127 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
130 char auth_params[500];
135 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
136 /** Client key used for digest signing */
137 static const uint8_t rtmp_player_key[] = {
138 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
139 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
141 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
142 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
143 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
146 #define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
147 /** Key used for RTMP server digest signing */
148 static const uint8_t rtmp_server_key[] = {
149 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
150 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
151 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
153 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
154 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
155 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
158 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
160 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
164 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
165 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
166 if ((err = av_reallocp(&rt->tracked_methods, rt->tracked_methods_size *
167 sizeof(*rt->tracked_methods))) < 0) {
168 rt->nb_tracked_methods = 0;
169 rt->tracked_methods_size = 0;
174 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
175 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
176 return AVERROR(ENOMEM);
177 rt->tracked_methods[rt->nb_tracked_methods].id = id;
178 rt->nb_tracked_methods++;
183 static void del_tracked_method(RTMPContext *rt, int index)
185 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
186 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
187 rt->nb_tracked_methods--;
190 static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
191 char **tracked_method)
193 RTMPContext *rt = s->priv_data;
199 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
200 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
203 for (i = 0; i < rt->nb_tracked_methods; i++) {
204 if (rt->tracked_methods[i].id != pkt_id)
207 *tracked_method = rt->tracked_methods[i].name;
208 del_tracked_method(rt, i);
215 static void free_tracked_methods(RTMPContext *rt)
219 for (i = 0; i < rt->nb_tracked_methods; i ++)
220 av_freep(&rt->tracked_methods[i].name);
221 av_freep(&rt->tracked_methods);
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 a pause packet that either pauses or unpauses the current stream.
779 static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
785 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
788 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
791 pkt.extra = rt->stream_id;
794 ff_amf_write_string(&p, "pause");
795 ff_amf_write_number(&p, 0); //no tracking back responses
796 ff_amf_write_null(&p); //as usual, the first null param
797 ff_amf_write_bool(&p, pause); // pause or unpause
798 ff_amf_write_number(&p, timestamp); //where we pause the stream
800 return rtmp_send_packet(rt, &pkt, 1);
804 * Generate 'publish' call and send it to the server.
806 static int gen_publish(URLContext *s, RTMPContext *rt)
812 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
814 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
815 0, 30 + strlen(rt->playpath))) < 0)
818 pkt.extra = rt->stream_id;
821 ff_amf_write_string(&p, "publish");
822 ff_amf_write_number(&p, ++rt->nb_invokes);
823 ff_amf_write_null(&p);
824 ff_amf_write_string(&p, rt->playpath);
825 ff_amf_write_string(&p, "live");
827 return rtmp_send_packet(rt, &pkt, 1);
831 * Generate ping reply and send it to the server.
833 static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
839 if (ppkt->size < 6) {
840 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
842 return AVERROR_INVALIDDATA;
845 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
846 ppkt->timestamp + 1, 6)) < 0)
850 bytestream_put_be16(&p, 7);
851 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
853 return rtmp_send_packet(rt, &pkt, 0);
857 * Generate SWF verification message and send it to the server.
859 static int gen_swf_verification(URLContext *s, RTMPContext *rt)
865 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
866 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
871 bytestream_put_be16(&p, 27);
872 memcpy(p, rt->swfverification, 42);
874 return rtmp_send_packet(rt, &pkt, 0);
878 * Generate server bandwidth message and send it to the server.
880 static int gen_server_bw(URLContext *s, RTMPContext *rt)
886 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
891 bytestream_put_be32(&p, rt->server_bw);
893 return rtmp_send_packet(rt, &pkt, 0);
897 * Generate check bandwidth message and send it to the server.
899 static int gen_check_bw(URLContext *s, RTMPContext *rt)
905 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
910 ff_amf_write_string(&p, "_checkbw");
911 ff_amf_write_number(&p, ++rt->nb_invokes);
912 ff_amf_write_null(&p);
914 return rtmp_send_packet(rt, &pkt, 1);
918 * Generate report on bytes read so far and send it to the server.
920 static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
926 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
931 bytestream_put_be32(&p, rt->bytes_read);
933 return rtmp_send_packet(rt, &pkt, 0);
936 static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
937 const char *subscribe)
943 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
944 0, 27 + strlen(subscribe))) < 0)
948 ff_amf_write_string(&p, "FCSubscribe");
949 ff_amf_write_number(&p, ++rt->nb_invokes);
950 ff_amf_write_null(&p);
951 ff_amf_write_string(&p, subscribe);
953 return rtmp_send_packet(rt, &pkt, 1);
956 int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
957 const uint8_t *key, int keylen, uint8_t *dst)
960 uint8_t hmac_buf[64+32] = {0};
963 sha = av_sha_alloc();
965 return AVERROR(ENOMEM);
968 memcpy(hmac_buf, key, keylen);
970 av_sha_init(sha, 256);
971 av_sha_update(sha,key, keylen);
972 av_sha_final(sha, hmac_buf);
974 for (i = 0; i < 64; i++)
975 hmac_buf[i] ^= HMAC_IPAD_VAL;
977 av_sha_init(sha, 256);
978 av_sha_update(sha, hmac_buf, 64);
980 av_sha_update(sha, src, len);
981 } else { //skip 32 bytes used for storing digest
982 av_sha_update(sha, src, gap);
983 av_sha_update(sha, src + gap + 32, len - gap - 32);
985 av_sha_final(sha, hmac_buf + 64);
987 for (i = 0; i < 64; i++)
988 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
989 av_sha_init(sha, 256);
990 av_sha_update(sha, hmac_buf, 64+32);
991 av_sha_final(sha, dst);
998 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
1001 int i, digest_pos = 0;
1003 for (i = 0; i < 4; i++)
1004 digest_pos += buf[i + off];
1005 digest_pos = digest_pos % mod_val + add_val;
1011 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1012 * will be stored) into that packet.
1014 * @param buf handshake data (1536 bytes)
1015 * @param encrypted use an encrypted connection (RTMPE)
1016 * @return offset to the digest inside input data
1018 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1020 int ret, digest_pos;
1023 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1025 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1027 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1028 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1037 * Verify that the received server response has the expected digest value.
1039 * @param buf handshake data received from the server (1536 bytes)
1040 * @param off position to search digest offset from
1041 * @return 0 if digest is valid, digest position otherwise
1043 static int rtmp_validate_digest(uint8_t *buf, int off)
1046 int ret, digest_pos;
1048 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1050 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1051 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1056 if (!memcmp(digest, buf + digest_pos, 32))
1061 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1067 if (rt->swfhash_len != 32) {
1068 av_log(s, AV_LOG_ERROR,
1069 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1070 return AVERROR(EINVAL);
1073 p = &rt->swfverification[0];
1074 bytestream_put_byte(&p, 1);
1075 bytestream_put_byte(&p, 1);
1076 bytestream_put_be32(&p, rt->swfsize);
1077 bytestream_put_be32(&p, rt->swfsize);
1079 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1086 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1087 uint8_t **out_data, int64_t *out_size)
1089 z_stream zs = { 0 };
1094 zs.avail_in = in_size;
1095 zs.next_in = in_data;
1096 ret = inflateInit(&zs);
1098 return AVERROR_UNKNOWN;
1101 uint8_t tmp_buf[16384];
1103 zs.avail_out = sizeof(tmp_buf);
1104 zs.next_out = tmp_buf;
1106 ret = inflate(&zs, Z_NO_FLUSH);
1107 if (ret != Z_OK && ret != Z_STREAM_END) {
1108 ret = AVERROR_UNKNOWN;
1112 size = sizeof(tmp_buf) - zs.avail_out;
1113 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1114 ret = AVERROR(ENOMEM);
1119 memcpy(*out_data + *out_size, tmp_buf, size);
1121 } while (zs.avail_out == 0);
1129 static int rtmp_calc_swfhash(URLContext *s)
1131 RTMPContext *rt = s->priv_data;
1132 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1133 int64_t in_size, out_size;
1139 /* Get the SWF player file. */
1140 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1141 &s->interrupt_callback, NULL)) < 0) {
1142 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1146 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1151 if (!(in_data = av_malloc(in_size))) {
1152 ret = AVERROR(ENOMEM);
1156 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1160 ret = AVERROR_INVALIDDATA;
1164 if (!memcmp(in_data, "CWS", 3)) {
1165 /* Decompress the SWF player file using Zlib. */
1166 if (!(out_data = av_malloc(8))) {
1167 ret = AVERROR(ENOMEM);
1170 *in_data = 'F'; // magic stuff
1171 memcpy(out_data, in_data, 8);
1175 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1176 &out_data, &out_size)) < 0)
1179 av_log(s, AV_LOG_ERROR,
1180 "Zlib is required for decompressing the SWF player file.\n");
1181 ret = AVERROR(EINVAL);
1191 /* Compute the SHA256 hash of the SWF player file. */
1192 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1193 "Genuine Adobe Flash Player 001", 30,
1197 /* Set SWFVerification parameters. */
1198 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1199 rt->swfsize = swfsize;
1203 av_freep(&out_data);
1204 ffurl_close(stream);
1209 * Perform handshake with the server by means of exchanging pseudorandom data
1210 * signed with HMAC-SHA2 digest.
1212 * @return 0 if handshake succeeds, negative value otherwise
1214 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1217 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1218 3, // unencrypted data
1219 0, 0, 0, 0, // client uptime
1225 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1226 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1228 int server_pos, client_pos;
1229 uint8_t digest[32], signature[32];
1232 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1234 av_lfg_init(&rnd, 0xDEADC0DE);
1235 // generate handshake packet - 1536 bytes of pseudorandom data
1236 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1237 tosend[i] = av_lfg_get(&rnd) >> 24;
1239 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1240 /* When the client wants to use RTMPE, we have to change the command
1241 * byte to 0x06 which means to use encrypted data and we have to set
1242 * the flash version to at least 9.0.115.0. */
1249 /* Initialize the Diffie-Hellmann context and generate the public key
1250 * to send to the server. */
1251 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1255 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1259 if ((ret = ffurl_write(rt->stream, tosend,
1260 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1261 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1265 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1266 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1267 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1271 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1272 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1273 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1277 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1278 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1279 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1281 if (rt->is_input && serverdata[5] >= 3) {
1282 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1288 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1293 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1294 return AVERROR(EIO);
1298 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1299 * key are the last 32 bytes of the server handshake. */
1301 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1302 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1306 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1307 rtmp_server_key, sizeof(rtmp_server_key),
1312 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1313 0, digest, 32, signature);
1317 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1318 /* Compute the shared secret key sent by the server and initialize
1319 * the RC4 encryption. */
1320 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1321 tosend + 1, type)) < 0)
1324 /* Encrypt the signature received by the server. */
1325 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1328 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1329 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1330 return AVERROR(EIO);
1333 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1334 tosend[i] = av_lfg_get(&rnd) >> 24;
1335 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1336 rtmp_player_key, sizeof(rtmp_player_key),
1341 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1343 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1347 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1348 /* Encrypt the signature to be send to the server. */
1349 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1350 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1354 // write reply back to the server
1355 if ((ret = ffurl_write(rt->stream, tosend,
1356 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1359 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1360 /* Set RC4 keys for encryption and update the keystreams. */
1361 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1365 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1366 /* Compute the shared secret key sent by the server and initialize
1367 * the RC4 encryption. */
1368 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1369 tosend + 1, 1)) < 0)
1372 if (serverdata[0] == 9) {
1373 /* Encrypt the signature received by the server. */
1374 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1379 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1380 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1383 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1384 /* Set RC4 keys for encryption and update the keystreams. */
1385 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1393 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1394 uint32_t *second_int, char *arraydata,
1399 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1400 RTMP_HANDSHAKE_PACKET_SIZE);
1402 return AVERROR(EIO);
1403 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1404 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1405 " not following standard\n", (int)inoutsize);
1406 return AVERROR(EINVAL);
1409 *first_int = AV_RB32(arraydata);
1410 *second_int = AV_RB32(arraydata + 4);
1414 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1415 uint32_t second_int, char *arraydata, int size)
1419 AV_WB32(arraydata, first_int);
1420 AV_WB32(arraydata + 4, second_int);
1421 inoutsize = ffurl_write(rt->stream, arraydata,
1422 RTMP_HANDSHAKE_PACKET_SIZE);
1423 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1424 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1425 return AVERROR(EIO);
1432 * rtmp handshake server side
1434 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1436 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1438 uint32_t hs_my_epoch;
1439 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1440 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1447 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1448 if (inoutsize <= 0) {
1449 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1450 return AVERROR(EIO);
1453 if (buffer[0] != 3) {
1454 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1455 return AVERROR(EIO);
1457 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1458 av_log(s, AV_LOG_ERROR,
1459 "Unable to write answer - RTMP S0\n");
1460 return AVERROR(EIO);
1463 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1464 RTMP_HANDSHAKE_PACKET_SIZE);
1466 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1470 /* By now same epoch will be sent */
1471 hs_my_epoch = hs_epoch;
1472 /* Generate random */
1473 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1475 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1477 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1478 RTMP_HANDSHAKE_PACKET_SIZE);
1480 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1484 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1485 RTMP_HANDSHAKE_PACKET_SIZE);
1487 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1491 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1492 RTMP_HANDSHAKE_PACKET_SIZE);
1494 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1497 if (temp != hs_my_epoch)
1498 av_log(s, AV_LOG_WARNING,
1499 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1500 if (memcmp(buffer + 8, hs_s1 + 8,
1501 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1502 av_log(s, AV_LOG_WARNING,
1503 "Erroneous C2 Message random does not match up\n");
1508 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1510 RTMPContext *rt = s->priv_data;
1513 if (pkt->size < 4) {
1514 av_log(s, AV_LOG_ERROR,
1515 "Too short chunk size change packet (%d)\n",
1517 return AVERROR_INVALIDDATA;
1520 if (!rt->is_input) {
1521 /* Send the same chunk size change packet back to the server,
1522 * setting the outgoing chunk size to the same as the incoming one. */
1523 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1524 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1526 rt->out_chunk_size = AV_RB32(pkt->data);
1529 rt->in_chunk_size = AV_RB32(pkt->data);
1530 if (rt->in_chunk_size <= 0) {
1531 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1533 return AVERROR_INVALIDDATA;
1535 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1541 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1543 RTMPContext *rt = s->priv_data;
1546 if (pkt->size < 2) {
1547 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1549 return AVERROR_INVALIDDATA;
1552 t = AV_RB16(pkt->data);
1554 if ((ret = gen_pong(s, rt, pkt)) < 0)
1556 } else if (t == 26) {
1558 if ((ret = gen_swf_verification(s, rt)) < 0)
1561 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1568 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1570 RTMPContext *rt = s->priv_data;
1572 if (pkt->size < 4) {
1573 av_log(s, AV_LOG_ERROR,
1574 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1576 return AVERROR_INVALIDDATA;
1579 rt->client_report_size = AV_RB32(pkt->data);
1580 if (rt->client_report_size <= 0) {
1581 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1582 rt->client_report_size);
1583 return AVERROR_INVALIDDATA;
1586 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1587 rt->client_report_size >>= 1;
1592 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1594 RTMPContext *rt = s->priv_data;
1596 if (pkt->size < 4) {
1597 av_log(s, AV_LOG_ERROR,
1598 "Too short server bandwidth report packet (%d)\n",
1600 return AVERROR_INVALIDDATA;
1603 rt->server_bw = AV_RB32(pkt->data);
1604 if (rt->server_bw <= 0) {
1605 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1607 return AVERROR_INVALIDDATA;
1609 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1614 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1615 const char *opaque, const char *challenge)
1618 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1619 struct AVMD5 *md5 = av_md5_alloc();
1621 return AVERROR(ENOMEM);
1623 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1626 av_md5_update(md5, user, strlen(user));
1627 av_md5_update(md5, salt, strlen(salt));
1628 av_md5_update(md5, rt->password, strlen(rt->password));
1629 av_md5_final(md5, hash);
1630 av_base64_encode(hashstr, sizeof(hashstr), hash,
1633 av_md5_update(md5, hashstr, strlen(hashstr));
1635 av_md5_update(md5, opaque, strlen(opaque));
1637 av_md5_update(md5, challenge, strlen(challenge));
1638 av_md5_update(md5, challenge2, strlen(challenge2));
1639 av_md5_final(md5, hash);
1640 av_base64_encode(hashstr, sizeof(hashstr), hash,
1642 snprintf(rt->auth_params, sizeof(rt->auth_params),
1643 "?authmod=%s&user=%s&challenge=%s&response=%s",
1644 "adobe", user, challenge2, hashstr);
1646 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1647 "&opaque=%s", opaque);
1653 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1656 char hashstr1[33], hashstr2[33];
1657 const char *realm = "live";
1658 const char *method = "publish";
1659 const char *qop = "auth";
1660 const char *nc = "00000001";
1662 struct AVMD5 *md5 = av_md5_alloc();
1664 return AVERROR(ENOMEM);
1666 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1669 av_md5_update(md5, user, strlen(user));
1670 av_md5_update(md5, ":", 1);
1671 av_md5_update(md5, realm, strlen(realm));
1672 av_md5_update(md5, ":", 1);
1673 av_md5_update(md5, rt->password, strlen(rt->password));
1674 av_md5_final(md5, hash);
1675 ff_data_to_hex(hashstr1, hash, 16, 1);
1676 hashstr1[32] = '\0';
1679 av_md5_update(md5, method, strlen(method));
1680 av_md5_update(md5, ":/", 2);
1681 av_md5_update(md5, rt->app, strlen(rt->app));
1682 if (!strchr(rt->app, '/'))
1683 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1684 av_md5_final(md5, hash);
1685 ff_data_to_hex(hashstr2, hash, 16, 1);
1686 hashstr2[32] = '\0';
1689 av_md5_update(md5, hashstr1, strlen(hashstr1));
1690 av_md5_update(md5, ":", 1);
1692 av_md5_update(md5, nonce, strlen(nonce));
1693 av_md5_update(md5, ":", 1);
1694 av_md5_update(md5, nc, strlen(nc));
1695 av_md5_update(md5, ":", 1);
1696 av_md5_update(md5, cnonce, strlen(cnonce));
1697 av_md5_update(md5, ":", 1);
1698 av_md5_update(md5, qop, strlen(qop));
1699 av_md5_update(md5, ":", 1);
1700 av_md5_update(md5, hashstr2, strlen(hashstr2));
1701 av_md5_final(md5, hash);
1702 ff_data_to_hex(hashstr1, hash, 16, 1);
1704 snprintf(rt->auth_params, sizeof(rt->auth_params),
1705 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1706 "llnw", user, nonce, cnonce, nc, hashstr1);
1712 static int handle_connect_error(URLContext *s, const char *desc)
1714 RTMPContext *rt = s->priv_data;
1715 char buf[300], *ptr, authmod[15];
1717 const char *user = "", *salt = "", *opaque = NULL,
1718 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1720 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1721 !(cptr = strstr(desc, "authmod=llnw"))) {
1722 av_log(s, AV_LOG_ERROR,
1723 "Unknown connect error (unsupported authentication method?)\n");
1724 return AVERROR_UNKNOWN;
1726 cptr += strlen("authmod=");
1727 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1728 authmod[i++] = *cptr++;
1731 if (!rt->username[0] || !rt->password[0]) {
1732 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1733 return AVERROR_UNKNOWN;
1736 if (strstr(desc, "?reason=authfailed")) {
1737 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1738 return AVERROR_UNKNOWN;
1739 } else if (strstr(desc, "?reason=nosuchuser")) {
1740 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1741 return AVERROR_UNKNOWN;
1744 if (rt->auth_tried) {
1745 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1746 return AVERROR_UNKNOWN;
1749 rt->auth_params[0] = '\0';
1751 if (strstr(desc, "code=403 need auth")) {
1752 snprintf(rt->auth_params, sizeof(rt->auth_params),
1753 "?authmod=%s&user=%s", authmod, rt->username);
1757 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1758 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1759 return AVERROR_UNKNOWN;
1762 av_strlcpy(buf, cptr + 1, sizeof(buf));
1766 char *next = strchr(ptr, '&');
1767 char *value = strchr(ptr, '=');
1772 if (!strcmp(ptr, "user")) {
1774 } else if (!strcmp(ptr, "salt")) {
1776 } else if (!strcmp(ptr, "opaque")) {
1778 } else if (!strcmp(ptr, "challenge")) {
1780 } else if (!strcmp(ptr, "nonce")) {
1783 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1786 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1791 if (!strcmp(authmod, "adobe")) {
1792 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1795 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1803 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1805 RTMPContext *rt = s->priv_data;
1806 const uint8_t *data_end = pkt->data + pkt->size;
1807 char *tracked_method = NULL;
1808 int level = AV_LOG_ERROR;
1809 uint8_t tmpstr[256];
1812 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1815 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1816 "description", tmpstr, sizeof(tmpstr))) {
1817 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1818 !strcmp(tracked_method, "releaseStream") ||
1819 !strcmp(tracked_method, "FCSubscribe") ||
1820 !strcmp(tracked_method, "FCPublish"))) {
1821 /* Gracefully ignore Adobe-specific historical artifact errors. */
1822 level = AV_LOG_WARNING;
1824 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1825 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1827 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1828 ret = handle_connect_error(s, tmpstr);
1830 rt->do_reconnect = 1;
1831 level = AV_LOG_VERBOSE;
1834 ret = AVERROR_UNKNOWN;
1835 av_log(s, level, "Server error: %s\n", tmpstr);
1838 av_free(tracked_method);
1842 static int write_begin(URLContext *s)
1844 RTMPContext *rt = s->priv_data;
1846 RTMPPacket spkt = { 0 };
1849 // Send Stream Begin 1
1850 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1851 RTMP_PT_PING, 0, 6)) < 0) {
1852 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1856 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1857 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1858 bytestream2_put_be32(&pbc, rt->nb_streamid);
1860 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1861 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1863 ff_rtmp_packet_destroy(&spkt);
1868 static int write_status(URLContext *s, RTMPPacket *pkt,
1869 const char *status, const char *filename)
1871 RTMPContext *rt = s->priv_data;
1872 RTMPPacket spkt = { 0 };
1873 char statusmsg[128];
1877 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1879 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1880 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1885 spkt.extra = pkt->extra;
1886 ff_amf_write_string(&pp, "onStatus");
1887 ff_amf_write_number(&pp, 0);
1888 ff_amf_write_null(&pp);
1890 ff_amf_write_object_start(&pp);
1891 ff_amf_write_field_name(&pp, "level");
1892 ff_amf_write_string(&pp, "status");
1893 ff_amf_write_field_name(&pp, "code");
1894 ff_amf_write_string(&pp, status);
1895 ff_amf_write_field_name(&pp, "description");
1896 snprintf(statusmsg, sizeof(statusmsg),
1897 "%s is now published", filename);
1898 ff_amf_write_string(&pp, statusmsg);
1899 ff_amf_write_field_name(&pp, "details");
1900 ff_amf_write_string(&pp, filename);
1901 ff_amf_write_field_name(&pp, "clientid");
1902 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1903 ff_amf_write_string(&pp, statusmsg);
1904 ff_amf_write_object_end(&pp);
1906 spkt.size = pp - spkt.data;
1907 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1908 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1909 ff_rtmp_packet_destroy(&spkt);
1914 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1916 RTMPContext *rt = s->priv_data;
1922 const uint8_t *p = pkt->data;
1924 RTMPPacket spkt = { 0 };
1928 bytestream2_init(&gbc, p, pkt->size);
1929 if (ff_amf_read_string(&gbc, command, sizeof(command),
1931 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1932 return AVERROR_INVALIDDATA;
1935 ret = ff_amf_read_number(&gbc, &seqnum);
1938 ret = ff_amf_read_null(&gbc);
1941 if (!strcmp(command, "FCPublish") ||
1942 !strcmp(command, "publish")) {
1943 ret = ff_amf_read_string(&gbc, filename,
1944 sizeof(filename), &stringlen);
1947 pchar = strrchr(s->filename, '/');
1949 av_log(s, AV_LOG_WARNING,
1950 "Unable to find / in url %s, bad format\n",
1952 pchar = s->filename;
1955 if (strcmp(pchar, filename))
1956 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1957 " %s\n", filename, pchar);
1959 rt->state = STATE_RECEIVING;
1962 if (!strcmp(command, "FCPublish")) {
1963 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1965 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1966 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1970 ff_amf_write_string(&pp, "onFCPublish");
1971 } else if (!strcmp(command, "publish")) {
1972 ret = write_begin(s);
1976 // Send onStatus(NetStream.Publish.Start)
1977 return write_status(s, pkt, "NetStream.Publish.Start",
1979 } else if (!strcmp(command, "play")) {
1980 ret = write_begin(s);
1983 rt->state = STATE_SENDING;
1984 return write_status(s, pkt, "NetStream.Play.Start",
1987 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1989 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1990 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1994 ff_amf_write_string(&pp, "_result");
1995 ff_amf_write_number(&pp, seqnum);
1996 ff_amf_write_null(&pp);
1997 if (!strcmp(command, "createStream")) {
1999 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2000 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2001 ff_amf_write_number(&pp, rt->nb_streamid);
2002 /* By now we don't control which streams are removed in
2003 * deleteStream. There is no stream creation control
2004 * if a client creates more than 2^32 - 2 streams. */
2007 spkt.size = pp - spkt.data;
2008 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2009 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2010 ff_rtmp_packet_destroy(&spkt);
2015 * Read the AMF_NUMBER response ("_result") to a function call
2016 * (e.g. createStream()). This response should be made up of the AMF_STRING
2017 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2018 * successful response, we will return set the value to number (otherwise number
2019 * will not be changed).
2021 * @return 0 if reading the value succeeds, negative value otherwiss
2023 static int read_number_result(RTMPPacket *pkt, double *number)
2025 // We only need to fit "_result" in this.
2026 uint8_t strbuffer[8];
2031 bytestream2_init(&gbc, pkt->data, pkt->size);
2033 // Value 1/4: "_result" as AMF_STRING
2034 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2035 return AVERROR_INVALIDDATA;
2036 if (strcmp(strbuffer, "_result"))
2037 return AVERROR_INVALIDDATA;
2038 // Value 2/4: The callee reference number
2039 if (ff_amf_read_number(&gbc, &numbuffer))
2040 return AVERROR_INVALIDDATA;
2042 if (ff_amf_read_null(&gbc))
2043 return AVERROR_INVALIDDATA;
2044 // Value 4/4: The resonse as AMF_NUMBER
2045 if (ff_amf_read_number(&gbc, &numbuffer))
2046 return AVERROR_INVALIDDATA;
2048 *number = numbuffer;
2053 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2055 RTMPContext *rt = s->priv_data;
2056 char *tracked_method = NULL;
2059 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2062 if (!tracked_method) {
2063 /* Ignore this reply when the current method is not tracked. */
2067 if (!strcmp(tracked_method, "connect")) {
2068 if (!rt->is_input) {
2069 if ((ret = gen_release_stream(s, rt)) < 0)
2072 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2075 if ((ret = gen_server_bw(s, rt)) < 0)
2079 if ((ret = gen_create_stream(s, rt)) < 0)
2083 /* Send the FCSubscribe command when the name of live
2084 * stream is defined by the user or if it's a live stream. */
2085 if (rt->subscribe) {
2086 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2088 } else if (rt->live == -1) {
2089 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2093 } else if (!strcmp(tracked_method, "createStream")) {
2095 if (read_number_result(pkt, &stream_id)) {
2096 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2098 rt->stream_id = stream_id;
2101 if (!rt->is_input) {
2102 if ((ret = gen_publish(s, rt)) < 0)
2105 if (rt->live != -1) {
2106 if ((ret = gen_get_stream_length(s, rt)) < 0)
2109 if ((ret = gen_play(s, rt)) < 0)
2111 if ((ret = gen_buffer_time(s, rt)) < 0)
2114 } else if (!strcmp(tracked_method, "getStreamLength")) {
2115 if (read_number_result(pkt, &rt->duration)) {
2116 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2121 av_free(tracked_method);
2125 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2127 RTMPContext *rt = s->priv_data;
2128 const uint8_t *data_end = pkt->data + pkt->size;
2129 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2130 uint8_t tmpstr[256];
2133 for (i = 0; i < 2; i++) {
2134 t = ff_amf_tag_size(ptr, data_end);
2140 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2141 if (!t && !strcmp(tmpstr, "error")) {
2142 t = ff_amf_get_field_value(ptr, data_end,
2143 "description", tmpstr, sizeof(tmpstr));
2144 if (t || !tmpstr[0])
2145 t = ff_amf_get_field_value(ptr, data_end, "code",
2146 tmpstr, sizeof(tmpstr));
2148 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2152 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2153 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2154 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2155 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2156 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2157 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2162 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2164 RTMPContext *rt = s->priv_data;
2167 //TODO: check for the messages sent for wrong state?
2168 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2169 if ((ret = handle_invoke_error(s, pkt)) < 0)
2171 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2172 if ((ret = handle_invoke_result(s, pkt)) < 0)
2174 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2175 if ((ret = handle_invoke_status(s, pkt)) < 0)
2177 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2178 if ((ret = gen_check_bw(s, rt)) < 0)
2180 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2181 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2182 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2183 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2184 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2185 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2186 if ((ret = send_invoke_response(s, pkt)) < 0)
2193 static int update_offset(RTMPContext *rt, int size)
2197 // generate packet header and put data into buffer for FLV demuxer
2198 if (rt->flv_off < rt->flv_size) {
2199 // There is old unread data in the buffer, thus append at the end
2200 old_flv_size = rt->flv_size;
2201 rt->flv_size += size;
2203 // All data has been read, write the new data at the start of the buffer
2205 rt->flv_size = size;
2209 return old_flv_size;
2212 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2214 int old_flv_size, ret;
2216 const uint8_t *data = pkt->data + skip;
2217 const int size = pkt->size - skip;
2218 uint32_t ts = pkt->timestamp;
2220 if (pkt->type == RTMP_PT_AUDIO) {
2222 } else if (pkt->type == RTMP_PT_VIDEO) {
2226 old_flv_size = update_offset(rt, size + 15);
2228 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2229 rt->flv_size = rt->flv_off = 0;
2232 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2233 bytestream2_skip_p(&pbc, old_flv_size);
2234 bytestream2_put_byte(&pbc, pkt->type);
2235 bytestream2_put_be24(&pbc, size);
2236 bytestream2_put_be24(&pbc, ts);
2237 bytestream2_put_byte(&pbc, ts >> 24);
2238 bytestream2_put_be24(&pbc, 0);
2239 bytestream2_put_buffer(&pbc, data, size);
2240 bytestream2_put_be32(&pbc, 0);
2245 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2247 RTMPContext *rt = s->priv_data;
2248 uint8_t commandbuffer[64];
2249 char statusmsg[128];
2250 int stringlen, ret, skip = 0;
2253 bytestream2_init(&gbc, pkt->data, pkt->size);
2254 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2256 return AVERROR_INVALIDDATA;
2258 if (!strcmp(commandbuffer, "onMetaData")) {
2259 // metadata properties should be stored in a mixed array
2260 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2261 // We have found a metaData Array so flv can determine the streams
2263 rt->received_metadata = 1;
2264 // skip 32-bit max array index
2265 bytestream2_skip(&gbc, 4);
2266 while (bytestream2_get_bytes_left(&gbc) > 3) {
2267 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2269 return AVERROR_INVALIDDATA;
2270 // We do not care about the content of the property (yet).
2271 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2273 return AVERROR_INVALIDDATA;
2274 bytestream2_skip(&gbc, stringlen);
2276 // The presence of the following properties indicates that the
2277 // respective streams are present.
2278 if (!strcmp(statusmsg, "videocodecid")) {
2281 if (!strcmp(statusmsg, "audiocodecid")) {
2285 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2286 return AVERROR_INVALIDDATA;
2290 // Skip the @setDataFrame string and validate it is a notification
2291 if (!strcmp(commandbuffer, "@setDataFrame")) {
2292 skip = gbc.buffer - pkt->data;
2293 ret = ff_amf_read_string(&gbc, statusmsg,
2294 sizeof(statusmsg), &stringlen);
2296 return AVERROR_INVALIDDATA;
2299 return append_flv_data(rt, pkt, skip);
2303 * Parse received packet and possibly perform some action depending on
2304 * the packet contents.
2305 * @return 0 for no errors, negative values for serious errors which prevent
2306 * further communications, positive values for uncritical errors
2308 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2313 ff_rtmp_packet_dump(s, pkt);
2316 switch (pkt->type) {
2317 case RTMP_PT_BYTES_READ:
2318 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2320 case RTMP_PT_CHUNK_SIZE:
2321 if ((ret = handle_chunk_size(s, pkt)) < 0)
2325 if ((ret = handle_ping(s, pkt)) < 0)
2328 case RTMP_PT_CLIENT_BW:
2329 if ((ret = handle_client_bw(s, pkt)) < 0)
2332 case RTMP_PT_SERVER_BW:
2333 if ((ret = handle_server_bw(s, pkt)) < 0)
2336 case RTMP_PT_INVOKE:
2337 if ((ret = handle_invoke(s, pkt)) < 0)
2342 case RTMP_PT_METADATA:
2343 case RTMP_PT_NOTIFY:
2344 /* Audio, Video and Metadata packets are parsed in get_packet() */
2347 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2353 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2355 int ret, old_flv_size, type;
2356 const uint8_t *next;
2359 uint32_t ts, cts, pts = 0;
2361 old_flv_size = update_offset(rt, pkt->size);
2363 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2364 rt->flv_size = rt->flv_off = 0;
2369 p = rt->flv_data + old_flv_size;
2371 /* copy data while rewriting timestamps */
2372 ts = pkt->timestamp;
2374 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2375 type = bytestream_get_byte(&next);
2376 size = bytestream_get_be24(&next);
2377 cts = bytestream_get_be24(&next);
2378 cts |= bytestream_get_byte(&next) << 24;
2383 if (size + 3 + 4 > pkt->data + pkt->size - next)
2385 bytestream_put_byte(&p, type);
2386 bytestream_put_be24(&p, size);
2387 bytestream_put_be24(&p, ts);
2388 bytestream_put_byte(&p, ts >> 24);
2389 memcpy(p, next, size + 3 + 4);
2390 next += size + 3 + 4;
2393 if (p != rt->flv_data + rt->flv_size) {
2394 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2395 "RTMP_PT_METADATA packet\n");
2396 rt->flv_size = p - rt->flv_data;
2403 * Interact with the server by receiving and sending RTMP packets until
2404 * there is some significant data (media data or expected status notification).
2406 * @param s reading context
2407 * @param for_header non-zero value tells function to work until it
2408 * gets notification from the server that playing has been started,
2409 * otherwise function will work until some media data is received (or
2411 * @return 0 for successful operation, negative value in case of error
2413 static int get_packet(URLContext *s, int for_header)
2415 RTMPContext *rt = s->priv_data;
2418 if (rt->state == STATE_STOPPED)
2422 RTMPPacket rpkt = { 0 };
2423 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2424 rt->in_chunk_size, &rt->prev_pkt[0],
2425 &rt->nb_prev_pkt[0])) <= 0) {
2427 return AVERROR(EAGAIN);
2429 return AVERROR(EIO);
2433 // Track timestamp for later use
2434 rt->last_timestamp = rpkt.timestamp;
2436 rt->bytes_read += ret;
2437 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2438 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2439 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2441 rt->last_bytes_read = rt->bytes_read;
2444 ret = rtmp_parse_result(s, rt, &rpkt);
2446 // At this point we must check if we are in the seek state and continue
2447 // with the next packet. handle_invoke will get us out of this state
2448 // when the right message is encountered
2449 if (rt->state == STATE_SEEKING) {
2450 ff_rtmp_packet_destroy(&rpkt);
2451 // We continue, let the natural flow of things happen:
2452 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2456 if (ret < 0) {//serious error in current packet
2457 ff_rtmp_packet_destroy(&rpkt);
2460 if (rt->do_reconnect && for_header) {
2461 ff_rtmp_packet_destroy(&rpkt);
2464 if (rt->state == STATE_STOPPED) {
2465 ff_rtmp_packet_destroy(&rpkt);
2468 if (for_header && (rt->state == STATE_PLAYING ||
2469 rt->state == STATE_PUBLISHING ||
2470 rt->state == STATE_SENDING ||
2471 rt->state == STATE_RECEIVING)) {
2472 ff_rtmp_packet_destroy(&rpkt);
2475 if (!rpkt.size || !rt->is_input) {
2476 ff_rtmp_packet_destroy(&rpkt);
2479 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2480 ret = append_flv_data(rt, &rpkt, 0);
2481 ff_rtmp_packet_destroy(&rpkt);
2483 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2484 ret = handle_notify(s, &rpkt);
2485 ff_rtmp_packet_destroy(&rpkt);
2487 } else if (rpkt.type == RTMP_PT_METADATA) {
2488 ret = handle_metadata(rt, &rpkt);
2489 ff_rtmp_packet_destroy(&rpkt);
2492 ff_rtmp_packet_destroy(&rpkt);
2496 static int rtmp_close(URLContext *h)
2498 RTMPContext *rt = h->priv_data;
2501 if (!rt->is_input) {
2502 rt->flv_data = NULL;
2503 if (rt->out_pkt.size)
2504 ff_rtmp_packet_destroy(&rt->out_pkt);
2505 if (rt->state > STATE_FCPUBLISH)
2506 ret = gen_fcunpublish_stream(h, rt);
2508 if (rt->state > STATE_HANDSHAKED)
2509 ret = gen_delete_stream(h, rt);
2510 for (i = 0; i < 2; i++) {
2511 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2512 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2513 av_freep(&rt->prev_pkt[i]);
2516 free_tracked_methods(rt);
2517 av_freep(&rt->flv_data);
2518 ffurl_close(rt->stream);
2523 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2524 * demuxer about the duration of the stream.
2526 * This should only be done if there was no real onMetadata packet sent by the
2527 * server at the start of the stream and if we were able to retrieve a valid
2528 * duration via a getStreamLength call.
2530 * @return 0 for successful operation, negative value in case of error
2532 static int inject_fake_duration_metadata(RTMPContext *rt)
2534 // We need to insert the metdata packet directly after the FLV
2535 // header, i.e. we need to move all other already read data by the
2536 // size of our fake metadata packet.
2539 // Keep old flv_data pointer
2540 uint8_t* old_flv_data = rt->flv_data;
2541 // Allocate a new flv_data pointer with enough space for the additional package
2542 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2543 rt->flv_data = old_flv_data;
2544 return AVERROR(ENOMEM);
2548 memcpy(rt->flv_data, old_flv_data, 13);
2549 // Copy remaining packets
2550 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2551 // Increase the size by the injected packet
2553 // Delete the old FLV data
2554 av_freep(&old_flv_data);
2556 p = rt->flv_data + 13;
2557 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2558 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2559 bytestream_put_be24(&p, 0); // timestamp
2560 bytestream_put_be32(&p, 0); // reserved
2562 // first event name as a string
2563 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2564 // "onMetaData" as AMF string
2565 bytestream_put_be16(&p, 10);
2566 bytestream_put_buffer(&p, "onMetaData", 10);
2568 // mixed array (hash) with size and string/type/data tuples
2569 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2570 bytestream_put_be32(&p, 1); // metadata_count
2572 // "duration" as AMF string
2573 bytestream_put_be16(&p, 8);
2574 bytestream_put_buffer(&p, "duration", 8);
2575 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2576 bytestream_put_be64(&p, av_double2int(rt->duration));
2579 bytestream_put_be16(&p, 0); // Empty string
2580 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2581 bytestream_put_be32(&p, 40); // size of data part (sum of all parts below)
2587 * Open RTMP connection and verify that the stream can be played.
2589 * URL syntax: rtmp://server[:port][/app][/playpath]
2590 * where 'app' is first one or two directories in the path
2591 * (e.g. /ondemand/, /flash/live/, etc.)
2592 * and 'playpath' is a file name (the rest of the path,
2593 * may be prefixed with "mp4:")
2595 static int rtmp_open(URLContext *s, const char *uri, int flags)
2597 RTMPContext *rt = s->priv_data;
2598 char proto[8], hostname[256], path[1024], auth[100], *fname;
2599 char *old_app, *qmark, *n, fname_buffer[1024];
2602 AVDictionary *opts = NULL;
2605 if (rt->listen_timeout > 0)
2608 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2610 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2611 hostname, sizeof(hostname), &port,
2612 path, sizeof(path), s->filename);
2614 n = strchr(path, ' ');
2616 av_log(s, AV_LOG_WARNING,
2617 "Detected librtmp style URL parameters, these aren't supported "
2618 "by the libavformat internal RTMP handler currently enabled. "
2619 "See the documentation for the correct way to pass parameters.\n");
2620 *n = '\0'; // Trim not supported part
2624 char *ptr = strchr(auth, ':');
2627 av_strlcpy(rt->username, auth, sizeof(rt->username));
2628 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2632 if (rt->listen && strcmp(proto, "rtmp")) {
2633 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2635 return AVERROR(EINVAL);
2637 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2638 if (!strcmp(proto, "rtmpts"))
2639 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2641 /* open the http tunneling connection */
2642 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2643 } else if (!strcmp(proto, "rtmps")) {
2644 /* open the tls connection */
2646 port = RTMPS_DEFAULT_PORT;
2647 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2648 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2649 if (!strcmp(proto, "rtmpte"))
2650 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2652 /* open the encrypted connection */
2653 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2656 /* open the tcp connection */
2658 port = RTMP_DEFAULT_PORT;
2660 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2661 "?listen&listen_timeout=%d",
2662 rt->listen_timeout * 1000);
2664 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2668 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2669 &s->interrupt_callback, &opts)) < 0) {
2670 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2674 if (rt->swfverify) {
2675 if ((ret = rtmp_calc_swfhash(s)) < 0)
2679 rt->state = STATE_START;
2680 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2682 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2685 rt->out_chunk_size = 128;
2686 rt->in_chunk_size = 128; // Probably overwritten later
2687 rt->state = STATE_HANDSHAKED;
2689 // Keep the application name when it has been defined by the user.
2692 rt->app = av_malloc(APP_MAX_LENGTH);
2694 ret = AVERROR(ENOMEM);
2698 //extract "app" part from path
2699 qmark = strchr(path, '?');
2700 if (qmark && strstr(qmark, "slist=")) {
2702 // After slist we have the playpath, before the params, the app
2703 av_strlcpy(rt->app, path + 1, FFMIN(qmark - path, APP_MAX_LENGTH));
2704 fname = strstr(path, "slist=") + 6;
2705 // Strip any further query parameters from fname
2706 amp = strchr(fname, '&');
2708 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2709 sizeof(fname_buffer)));
2710 fname = fname_buffer;
2712 } else if (!strncmp(path, "/ondemand/", 10)) {
2714 memcpy(rt->app, "ondemand", 9);
2716 char *next = *path ? path + 1 : path;
2717 char *p = strchr(next, '/');
2720 // If name of application has been defined by the user, assume that
2721 // playpath is provided in the URL
2725 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2728 // make sure we do not mismatch a playpath for an application instance
2729 char *c = strchr(p + 1, ':');
2730 fname = strchr(p + 1, '/');
2731 if (!fname || (c && c < fname)) {
2733 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2736 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2742 // The name of application has been defined by the user, override it.
2743 if (strlen(old_app) >= APP_MAX_LENGTH) {
2744 ret = AVERROR(EINVAL);
2751 if (!rt->playpath) {
2752 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2753 if (!rt->playpath) {
2754 ret = AVERROR(ENOMEM);
2759 int len = strlen(fname);
2760 if (!strchr(fname, ':') && len >= 4 &&
2761 (!strcmp(fname + len - 4, ".f4v") ||
2762 !strcmp(fname + len - 4, ".mp4"))) {
2763 memcpy(rt->playpath, "mp4:", 5);
2765 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2766 fname[len - 4] = '\0';
2767 rt->playpath[0] = 0;
2769 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2771 rt->playpath[0] = '\0';
2776 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2778 ret = AVERROR(ENOMEM);
2781 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2782 port, "/%s", rt->app);
2785 if (!rt->flashver) {
2786 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2787 if (!rt->flashver) {
2788 ret = AVERROR(ENOMEM);
2792 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2793 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2794 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2796 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2797 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2801 rt->client_report_size = 1048576;
2805 rt->received_metadata = 0;
2806 rt->last_bytes_read = 0;
2807 rt->server_bw = 2500000;
2810 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2811 proto, path, rt->app, rt->playpath);
2813 if ((ret = gen_connect(s, rt)) < 0)
2816 if ((ret = read_connect(s, s->priv_data)) < 0)
2821 ret = get_packet(s, 1);
2822 } while (ret == AVERROR(EAGAIN));
2826 if (rt->do_reconnect) {
2828 ffurl_close(rt->stream);
2830 rt->do_reconnect = 0;
2832 for (i = 0; i < 2; i++)
2833 memset(rt->prev_pkt[i], 0,
2834 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2835 free_tracked_methods(rt);
2840 // generate FLV header for demuxer
2842 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2845 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2847 // Read packets until we reach the first A/V packet or read metadata.
2848 // If there was a metadata package in front of the A/V packets, we can
2849 // build the FLV header from this. If we do not receive any metadata,
2850 // the FLV decoder will allocate the needed streams when their first
2851 // audio or video packet arrives.
2852 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2853 if ((ret = get_packet(s, 0)) < 0)
2857 // Either after we have read the metadata or (if there is none) the
2858 // first packet of an A/V stream, we have a better knowledge about the
2859 // streams, so set the FLV header accordingly.
2860 if (rt->has_audio) {
2861 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2863 if (rt->has_video) {
2864 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2867 // If we received the first packet of an A/V stream and no metadata but
2868 // the server returned a valid duration, create a fake metadata packet
2869 // to inform the FLV decoder about the duration.
2870 if (!rt->received_metadata && rt->duration > 0) {
2871 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2876 rt->flv_data = NULL;
2878 rt->skip_bytes = 13;
2881 s->max_packet_size = rt->stream->max_packet_size;
2886 av_dict_free(&opts);
2891 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2893 RTMPContext *rt = s->priv_data;
2894 int orig_size = size;
2898 int data_left = rt->flv_size - rt->flv_off;
2900 if (data_left >= size) {
2901 memcpy(buf, rt->flv_data + rt->flv_off, size);
2902 rt->flv_off += size;
2905 if (data_left > 0) {
2906 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2909 rt->flv_off = rt->flv_size;
2912 if ((ret = get_packet(s, 0)) < 0)
2918 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2921 RTMPContext *rt = s->priv_data;
2923 av_log(s, AV_LOG_DEBUG,
2924 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2925 stream_index, timestamp, flags);
2926 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2927 av_log(s, AV_LOG_ERROR,
2928 "Unable to send seek command on stream index %d at timestamp "
2929 "%"PRId64" with flags %08x\n",
2930 stream_index, timestamp, flags);
2933 rt->flv_off = rt->flv_size;
2934 rt->state = STATE_SEEKING;
2938 static int rtmp_pause(URLContext *s, int pause)
2940 RTMPContext *rt = s->priv_data;
2942 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2943 rt->last_timestamp);
2944 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2945 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2946 rt->last_timestamp);
2952 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2954 RTMPContext *rt = s->priv_data;
2955 int size_temp = size;
2956 int pktsize, pkttype, copy;
2958 const uint8_t *buf_temp = buf;
2963 if (rt->skip_bytes) {
2964 int skip = FFMIN(rt->skip_bytes, size_temp);
2967 rt->skip_bytes -= skip;
2971 if (rt->flv_header_bytes < RTMP_HEADER) {
2972 const uint8_t *header = rt->flv_header;
2973 int channel = RTMP_AUDIO_CHANNEL;
2975 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2976 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2977 rt->flv_header_bytes += copy;
2979 if (rt->flv_header_bytes < RTMP_HEADER)
2982 pkttype = bytestream_get_byte(&header);
2983 pktsize = bytestream_get_be24(&header);
2984 ts = bytestream_get_be24(&header);
2985 ts |= bytestream_get_byte(&header) << 24;
2986 bytestream_get_be24(&header);
2987 rt->flv_size = pktsize;
2989 if (pkttype == RTMP_PT_VIDEO)
2990 channel = RTMP_VIDEO_CHANNEL;
2992 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2993 pkttype == RTMP_PT_NOTIFY) {
2994 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2995 &rt->nb_prev_pkt[1],
2998 // Force sending a full 12 bytes header by clearing the
2999 // channel id, to make it not match a potential earlier
3000 // packet in the same channel.
3001 rt->prev_pkt[1][channel].channel_id = 0;
3004 //this can be a big packet, it's better to send it right here
3005 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3006 pkttype, ts, pktsize)) < 0)
3009 rt->out_pkt.extra = rt->stream_id;
3010 rt->flv_data = rt->out_pkt.data;
3013 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3014 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3015 rt->flv_off += copy;
3018 if (rt->flv_off == rt->flv_size) {
3021 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3022 // For onMetaData and |RtmpSampleAccess packets, we want
3023 // @setDataFrame prepended to the packet before it gets sent.
3024 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3026 uint8_t commandbuffer[64];
3030 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3031 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3033 if (!strcmp(commandbuffer, "onMetaData") ||
3034 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3036 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3037 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3040 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3041 rt->out_pkt.size += 16;
3042 ptr = rt->out_pkt.data;
3043 ff_amf_write_string(&ptr, "@setDataFrame");
3048 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3052 rt->flv_header_bytes = 0;
3053 rt->flv_nb_packets++;
3055 } while (buf_temp - buf < size);
3057 if (rt->flv_nb_packets < rt->flush_interval)
3059 rt->flv_nb_packets = 0;
3061 /* set stream into nonblocking mode */
3062 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3064 /* try to read one byte from the stream */
3065 ret = ffurl_read(rt->stream, &c, 1);
3067 /* switch the stream back into blocking mode */
3068 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3070 if (ret == AVERROR(EAGAIN)) {
3071 /* no incoming data to handle */
3073 } else if (ret < 0) {
3075 } else if (ret == 1) {
3076 RTMPPacket rpkt = { 0 };
3078 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3081 &rt->nb_prev_pkt[0], c)) <= 0)
3084 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3087 ff_rtmp_packet_destroy(&rpkt);
3093 #define OFFSET(x) offsetof(RTMPContext, x)
3094 #define DEC AV_OPT_FLAG_DECODING_PARAM
3095 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3097 static const AVOption rtmp_options[] = {
3098 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3099 {"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},
3100 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3101 {"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},
3102 {"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},
3103 {"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"},
3104 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3105 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3106 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3107 {"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},
3108 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3109 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3110 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3111 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3112 {"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},
3113 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3114 {"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},
3115 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3116 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3117 {"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" },
3121 #define RTMP_PROTOCOL(flavor) \
3122 static const AVClass flavor##_class = { \
3123 .class_name = #flavor, \
3124 .item_name = av_default_item_name, \
3125 .option = rtmp_options, \
3126 .version = LIBAVUTIL_VERSION_INT, \
3129 URLProtocol ff_##flavor##_protocol = { \
3131 .url_open = rtmp_open, \
3132 .url_read = rtmp_read, \
3133 .url_read_seek = rtmp_seek, \
3134 .url_read_pause = rtmp_pause, \
3135 .url_write = rtmp_write, \
3136 .url_close = rtmp_close, \
3137 .priv_data_size = sizeof(RTMPContext), \
3138 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3139 .priv_data_class= &flavor##_class, \
3144 RTMP_PROTOCOL(rtmpe)
3145 RTMP_PROTOCOL(rtmps)
3146 RTMP_PROTOCOL(rtmpt)
3147 RTMP_PROTOCOL(rtmpte)
3148 RTMP_PROTOCOL(rtmpts)