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/hmac.h"
31 #include "libavutil/intfloat.h"
32 #include "libavutil/lfg.h"
33 #include "libavutil/md5.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/random_seed.h"
43 #include "rtmpcrypt.h"
51 #define APP_MAX_LENGTH 1024
52 #define PLAYPATH_MAX_LENGTH 512
53 #define TCURL_MAX_LENGTH 1024
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)
961 hmac = av_hmac_alloc(AV_HMAC_SHA256);
963 return AVERROR(ENOMEM);
965 av_hmac_init(hmac, key, keylen);
967 av_hmac_update(hmac, src, len);
968 } else { //skip 32 bytes used for storing digest
969 av_hmac_update(hmac, src, gap);
970 av_hmac_update(hmac, src + gap + 32, len - gap - 32);
972 av_hmac_final(hmac, dst, 32);
979 int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
982 int i, digest_pos = 0;
984 for (i = 0; i < 4; i++)
985 digest_pos += buf[i + off];
986 digest_pos = digest_pos % mod_val + add_val;
992 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
993 * will be stored) into that packet.
995 * @param buf handshake data (1536 bytes)
996 * @param encrypted use an encrypted connection (RTMPE)
997 * @return offset to the digest inside input data
999 static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
1001 int ret, digest_pos;
1004 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1006 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1008 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1009 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
1018 * Verify that the received server response has the expected digest value.
1020 * @param buf handshake data received from the server (1536 bytes)
1021 * @param off position to search digest offset from
1022 * @return 0 if digest is valid, digest position otherwise
1024 static int rtmp_validate_digest(uint8_t *buf, int off)
1027 int ret, digest_pos;
1029 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1031 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1032 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
1037 if (!memcmp(digest, buf + digest_pos, 32))
1042 static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
1048 if (rt->swfhash_len != 32) {
1049 av_log(s, AV_LOG_ERROR,
1050 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1051 return AVERROR(EINVAL);
1054 p = &rt->swfverification[0];
1055 bytestream_put_byte(&p, 1);
1056 bytestream_put_byte(&p, 1);
1057 bytestream_put_be32(&p, rt->swfsize);
1058 bytestream_put_be32(&p, rt->swfsize);
1060 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1067 static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1068 uint8_t **out_data, int64_t *out_size)
1070 z_stream zs = { 0 };
1075 zs.avail_in = in_size;
1076 zs.next_in = in_data;
1077 ret = inflateInit(&zs);
1079 return AVERROR_UNKNOWN;
1082 uint8_t tmp_buf[16384];
1084 zs.avail_out = sizeof(tmp_buf);
1085 zs.next_out = tmp_buf;
1087 ret = inflate(&zs, Z_NO_FLUSH);
1088 if (ret != Z_OK && ret != Z_STREAM_END) {
1089 ret = AVERROR_UNKNOWN;
1093 size = sizeof(tmp_buf) - zs.avail_out;
1094 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1095 ret = AVERROR(ENOMEM);
1100 memcpy(*out_data + *out_size, tmp_buf, size);
1102 } while (zs.avail_out == 0);
1110 static int rtmp_calc_swfhash(URLContext *s)
1112 RTMPContext *rt = s->priv_data;
1113 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1114 int64_t in_size, out_size;
1120 /* Get the SWF player file. */
1121 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1122 &s->interrupt_callback, NULL,
1123 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1124 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1128 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1133 if (!(in_data = av_malloc(in_size))) {
1134 ret = AVERROR(ENOMEM);
1138 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1142 ret = AVERROR_INVALIDDATA;
1146 if (!memcmp(in_data, "CWS", 3)) {
1147 /* Decompress the SWF player file using Zlib. */
1148 if (!(out_data = av_malloc(8))) {
1149 ret = AVERROR(ENOMEM);
1152 *in_data = 'F'; // magic stuff
1153 memcpy(out_data, in_data, 8);
1157 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1158 &out_data, &out_size)) < 0)
1161 av_log(s, AV_LOG_ERROR,
1162 "Zlib is required for decompressing the SWF player file.\n");
1163 ret = AVERROR(EINVAL);
1173 /* Compute the SHA256 hash of the SWF player file. */
1174 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1175 "Genuine Adobe Flash Player 001", 30,
1179 /* Set SWFVerification parameters. */
1180 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1181 rt->swfsize = swfsize;
1185 av_freep(&out_data);
1186 ffurl_close(stream);
1191 * Perform handshake with the server by means of exchanging pseudorandom data
1192 * signed with HMAC-SHA2 digest.
1194 * @return 0 if handshake succeeds, negative value otherwise
1196 static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1199 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1200 3, // unencrypted data
1201 0, 0, 0, 0, // client uptime
1207 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1208 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1210 int server_pos, client_pos;
1211 uint8_t digest[32], signature[32];
1214 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1216 av_lfg_init(&rnd, 0xDEADC0DE);
1217 // generate handshake packet - 1536 bytes of pseudorandom data
1218 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1219 tosend[i] = av_lfg_get(&rnd) >> 24;
1221 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1222 /* When the client wants to use RTMPE, we have to change the command
1223 * byte to 0x06 which means to use encrypted data and we have to set
1224 * the flash version to at least 9.0.115.0. */
1231 /* Initialize the Diffie-Hellmann context and generate the public key
1232 * to send to the server. */
1233 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1237 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1241 if ((ret = ffurl_write(rt->stream, tosend,
1242 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1243 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1247 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1248 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1249 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1253 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1254 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
1255 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1259 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1260 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1261 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1263 if (rt->is_input && serverdata[5] >= 3) {
1264 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1270 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1275 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1276 return AVERROR(EIO);
1280 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1281 * key are the last 32 bytes of the server handshake. */
1283 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1284 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1288 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1289 rtmp_server_key, sizeof(rtmp_server_key),
1294 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1295 0, digest, 32, signature);
1299 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1300 /* Compute the shared secret key sent by the server and initialize
1301 * the RC4 encryption. */
1302 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1303 tosend + 1, type)) < 0)
1306 /* Encrypt the signature received by the server. */
1307 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1310 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1311 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1312 return AVERROR(EIO);
1315 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1316 tosend[i] = av_lfg_get(&rnd) >> 24;
1317 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1318 rtmp_player_key, sizeof(rtmp_player_key),
1323 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1325 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1329 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1330 /* Encrypt the signature to be send to the server. */
1331 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1332 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1336 // write reply back to the server
1337 if ((ret = ffurl_write(rt->stream, tosend,
1338 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1341 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1342 /* Set RC4 keys for encryption and update the keystreams. */
1343 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1347 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1348 /* Compute the shared secret key sent by the server and initialize
1349 * the RC4 encryption. */
1350 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1351 tosend + 1, 1)) < 0)
1354 if (serverdata[0] == 9) {
1355 /* Encrypt the signature received by the server. */
1356 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1361 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1362 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1365 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1366 /* Set RC4 keys for encryption and update the keystreams. */
1367 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1375 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1376 uint32_t *second_int, char *arraydata,
1381 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1382 RTMP_HANDSHAKE_PACKET_SIZE);
1384 return AVERROR(EIO);
1385 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1386 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1387 " not following standard\n", (int)inoutsize);
1388 return AVERROR(EINVAL);
1391 *first_int = AV_RB32(arraydata);
1392 *second_int = AV_RB32(arraydata + 4);
1396 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1397 uint32_t second_int, char *arraydata, int size)
1401 AV_WB32(arraydata, first_int);
1402 AV_WB32(arraydata + 4, second_int);
1403 inoutsize = ffurl_write(rt->stream, arraydata,
1404 RTMP_HANDSHAKE_PACKET_SIZE);
1405 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1406 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1407 return AVERROR(EIO);
1414 * rtmp handshake server side
1416 static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1418 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1420 uint32_t hs_my_epoch;
1421 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1422 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1429 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1430 if (inoutsize <= 0) {
1431 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1432 return AVERROR(EIO);
1435 if (buffer[0] != 3) {
1436 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1437 return AVERROR(EIO);
1439 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1440 av_log(s, AV_LOG_ERROR,
1441 "Unable to write answer - RTMP S0\n");
1442 return AVERROR(EIO);
1445 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1446 RTMP_HANDSHAKE_PACKET_SIZE);
1448 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1452 /* By now same epoch will be sent */
1453 hs_my_epoch = hs_epoch;
1454 /* Generate random */
1455 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1457 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1459 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1460 RTMP_HANDSHAKE_PACKET_SIZE);
1462 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1466 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1467 RTMP_HANDSHAKE_PACKET_SIZE);
1469 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1473 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1474 RTMP_HANDSHAKE_PACKET_SIZE);
1476 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1479 if (temp != hs_my_epoch)
1480 av_log(s, AV_LOG_WARNING,
1481 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1482 if (memcmp(buffer + 8, hs_s1 + 8,
1483 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1484 av_log(s, AV_LOG_WARNING,
1485 "Erroneous C2 Message random does not match up\n");
1490 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1492 RTMPContext *rt = s->priv_data;
1495 if (pkt->size < 4) {
1496 av_log(s, AV_LOG_ERROR,
1497 "Too short chunk size change packet (%d)\n",
1499 return AVERROR_INVALIDDATA;
1502 if (!rt->is_input) {
1503 /* Send the same chunk size change packet back to the server,
1504 * setting the outgoing chunk size to the same as the incoming one. */
1505 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1506 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1508 rt->out_chunk_size = AV_RB32(pkt->data);
1511 rt->in_chunk_size = AV_RB32(pkt->data);
1512 if (rt->in_chunk_size <= 0) {
1513 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1515 return AVERROR_INVALIDDATA;
1517 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1523 static int handle_ping(URLContext *s, RTMPPacket *pkt)
1525 RTMPContext *rt = s->priv_data;
1528 if (pkt->size < 2) {
1529 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1531 return AVERROR_INVALIDDATA;
1534 t = AV_RB16(pkt->data);
1536 if ((ret = gen_pong(s, rt, pkt)) < 0)
1538 } else if (t == 26) {
1540 if ((ret = gen_swf_verification(s, rt)) < 0)
1543 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1550 static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1552 RTMPContext *rt = s->priv_data;
1554 if (pkt->size < 4) {
1555 av_log(s, AV_LOG_ERROR,
1556 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1558 return AVERROR_INVALIDDATA;
1561 rt->client_report_size = AV_RB32(pkt->data);
1562 if (rt->client_report_size <= 0) {
1563 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1564 rt->client_report_size);
1565 return AVERROR_INVALIDDATA;
1568 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1569 rt->client_report_size >>= 1;
1574 static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1576 RTMPContext *rt = s->priv_data;
1578 if (pkt->size < 4) {
1579 av_log(s, AV_LOG_ERROR,
1580 "Too short server bandwidth report packet (%d)\n",
1582 return AVERROR_INVALIDDATA;
1585 rt->server_bw = AV_RB32(pkt->data);
1586 if (rt->server_bw <= 0) {
1587 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1589 return AVERROR_INVALIDDATA;
1591 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1596 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1597 const char *opaque, const char *challenge)
1600 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1601 struct AVMD5 *md5 = av_md5_alloc();
1603 return AVERROR(ENOMEM);
1605 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1608 av_md5_update(md5, user, strlen(user));
1609 av_md5_update(md5, salt, strlen(salt));
1610 av_md5_update(md5, rt->password, strlen(rt->password));
1611 av_md5_final(md5, hash);
1612 av_base64_encode(hashstr, sizeof(hashstr), hash,
1615 av_md5_update(md5, hashstr, strlen(hashstr));
1617 av_md5_update(md5, opaque, strlen(opaque));
1619 av_md5_update(md5, challenge, strlen(challenge));
1620 av_md5_update(md5, challenge2, strlen(challenge2));
1621 av_md5_final(md5, hash);
1622 av_base64_encode(hashstr, sizeof(hashstr), hash,
1624 snprintf(rt->auth_params, sizeof(rt->auth_params),
1625 "?authmod=%s&user=%s&challenge=%s&response=%s",
1626 "adobe", user, challenge2, hashstr);
1628 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1629 "&opaque=%s", opaque);
1635 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1638 char hashstr1[33], hashstr2[33];
1639 const char *realm = "live";
1640 const char *method = "publish";
1641 const char *qop = "auth";
1642 const char *nc = "00000001";
1644 struct AVMD5 *md5 = av_md5_alloc();
1646 return AVERROR(ENOMEM);
1648 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1651 av_md5_update(md5, user, strlen(user));
1652 av_md5_update(md5, ":", 1);
1653 av_md5_update(md5, realm, strlen(realm));
1654 av_md5_update(md5, ":", 1);
1655 av_md5_update(md5, rt->password, strlen(rt->password));
1656 av_md5_final(md5, hash);
1657 ff_data_to_hex(hashstr1, hash, 16, 1);
1658 hashstr1[32] = '\0';
1661 av_md5_update(md5, method, strlen(method));
1662 av_md5_update(md5, ":/", 2);
1663 av_md5_update(md5, rt->app, strlen(rt->app));
1664 if (!strchr(rt->app, '/'))
1665 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1666 av_md5_final(md5, hash);
1667 ff_data_to_hex(hashstr2, hash, 16, 1);
1668 hashstr2[32] = '\0';
1671 av_md5_update(md5, hashstr1, strlen(hashstr1));
1672 av_md5_update(md5, ":", 1);
1674 av_md5_update(md5, nonce, strlen(nonce));
1675 av_md5_update(md5, ":", 1);
1676 av_md5_update(md5, nc, strlen(nc));
1677 av_md5_update(md5, ":", 1);
1678 av_md5_update(md5, cnonce, strlen(cnonce));
1679 av_md5_update(md5, ":", 1);
1680 av_md5_update(md5, qop, strlen(qop));
1681 av_md5_update(md5, ":", 1);
1682 av_md5_update(md5, hashstr2, strlen(hashstr2));
1683 av_md5_final(md5, hash);
1684 ff_data_to_hex(hashstr1, hash, 16, 1);
1686 snprintf(rt->auth_params, sizeof(rt->auth_params),
1687 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1688 "llnw", user, nonce, cnonce, nc, hashstr1);
1694 static int handle_connect_error(URLContext *s, const char *desc)
1696 RTMPContext *rt = s->priv_data;
1697 char buf[300], *ptr, authmod[15];
1699 const char *user = "", *salt = "", *opaque = NULL,
1700 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1702 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1703 !(cptr = strstr(desc, "authmod=llnw"))) {
1704 av_log(s, AV_LOG_ERROR,
1705 "Unknown connect error (unsupported authentication method?)\n");
1706 return AVERROR_UNKNOWN;
1708 cptr += strlen("authmod=");
1709 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1710 authmod[i++] = *cptr++;
1713 if (!rt->username[0] || !rt->password[0]) {
1714 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1715 return AVERROR_UNKNOWN;
1718 if (strstr(desc, "?reason=authfailed")) {
1719 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1720 return AVERROR_UNKNOWN;
1721 } else if (strstr(desc, "?reason=nosuchuser")) {
1722 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1723 return AVERROR_UNKNOWN;
1726 if (rt->auth_tried) {
1727 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1728 return AVERROR_UNKNOWN;
1731 rt->auth_params[0] = '\0';
1733 if (strstr(desc, "code=403 need auth")) {
1734 snprintf(rt->auth_params, sizeof(rt->auth_params),
1735 "?authmod=%s&user=%s", authmod, rt->username);
1739 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1740 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1741 return AVERROR_UNKNOWN;
1744 av_strlcpy(buf, cptr + 1, sizeof(buf));
1748 char *next = strchr(ptr, '&');
1749 char *value = strchr(ptr, '=');
1754 if (!strcmp(ptr, "user")) {
1756 } else if (!strcmp(ptr, "salt")) {
1758 } else if (!strcmp(ptr, "opaque")) {
1760 } else if (!strcmp(ptr, "challenge")) {
1762 } else if (!strcmp(ptr, "nonce")) {
1765 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1768 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1773 if (!strcmp(authmod, "adobe")) {
1774 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1777 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1785 static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1787 RTMPContext *rt = s->priv_data;
1788 const uint8_t *data_end = pkt->data + pkt->size;
1789 char *tracked_method = NULL;
1790 int level = AV_LOG_ERROR;
1791 uint8_t tmpstr[256];
1794 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1797 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1798 "description", tmpstr, sizeof(tmpstr))) {
1799 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1800 !strcmp(tracked_method, "releaseStream") ||
1801 !strcmp(tracked_method, "FCSubscribe") ||
1802 !strcmp(tracked_method, "FCPublish"))) {
1803 /* Gracefully ignore Adobe-specific historical artifact errors. */
1804 level = AV_LOG_WARNING;
1806 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1807 level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1809 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1810 ret = handle_connect_error(s, tmpstr);
1812 rt->do_reconnect = 1;
1813 level = AV_LOG_VERBOSE;
1816 ret = AVERROR_UNKNOWN;
1817 av_log(s, level, "Server error: %s\n", tmpstr);
1820 av_free(tracked_method);
1824 static int write_begin(URLContext *s)
1826 RTMPContext *rt = s->priv_data;
1828 RTMPPacket spkt = { 0 };
1831 // Send Stream Begin 1
1832 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1833 RTMP_PT_PING, 0, 6)) < 0) {
1834 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1838 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1839 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1840 bytestream2_put_be32(&pbc, rt->nb_streamid);
1842 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1843 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1845 ff_rtmp_packet_destroy(&spkt);
1850 static int write_status(URLContext *s, RTMPPacket *pkt,
1851 const char *status, const char *filename)
1853 RTMPContext *rt = s->priv_data;
1854 RTMPPacket spkt = { 0 };
1855 char statusmsg[128];
1859 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1861 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1862 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1867 spkt.extra = pkt->extra;
1868 ff_amf_write_string(&pp, "onStatus");
1869 ff_amf_write_number(&pp, 0);
1870 ff_amf_write_null(&pp);
1872 ff_amf_write_object_start(&pp);
1873 ff_amf_write_field_name(&pp, "level");
1874 ff_amf_write_string(&pp, "status");
1875 ff_amf_write_field_name(&pp, "code");
1876 ff_amf_write_string(&pp, status);
1877 ff_amf_write_field_name(&pp, "description");
1878 snprintf(statusmsg, sizeof(statusmsg),
1879 "%s is now published", filename);
1880 ff_amf_write_string(&pp, statusmsg);
1881 ff_amf_write_field_name(&pp, "details");
1882 ff_amf_write_string(&pp, filename);
1883 ff_amf_write_field_name(&pp, "clientid");
1884 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1885 ff_amf_write_string(&pp, statusmsg);
1886 ff_amf_write_object_end(&pp);
1888 spkt.size = pp - spkt.data;
1889 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1890 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1891 ff_rtmp_packet_destroy(&spkt);
1896 static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1898 RTMPContext *rt = s->priv_data;
1904 const uint8_t *p = pkt->data;
1906 RTMPPacket spkt = { 0 };
1910 bytestream2_init(&gbc, p, pkt->size);
1911 if (ff_amf_read_string(&gbc, command, sizeof(command),
1913 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1914 return AVERROR_INVALIDDATA;
1917 ret = ff_amf_read_number(&gbc, &seqnum);
1920 ret = ff_amf_read_null(&gbc);
1923 if (!strcmp(command, "FCPublish") ||
1924 !strcmp(command, "publish")) {
1925 ret = ff_amf_read_string(&gbc, filename,
1926 sizeof(filename), &stringlen);
1929 pchar = strrchr(s->filename, '/');
1931 av_log(s, AV_LOG_WARNING,
1932 "Unable to find / in url %s, bad format\n",
1934 pchar = s->filename;
1937 if (strcmp(pchar, filename))
1938 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1939 " %s\n", filename, pchar);
1941 rt->state = STATE_RECEIVING;
1944 if (!strcmp(command, "FCPublish")) {
1945 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1947 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1948 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1952 ff_amf_write_string(&pp, "onFCPublish");
1953 } else if (!strcmp(command, "publish")) {
1954 ret = write_begin(s);
1958 // Send onStatus(NetStream.Publish.Start)
1959 return write_status(s, pkt, "NetStream.Publish.Start",
1961 } else if (!strcmp(command, "play")) {
1962 ret = write_begin(s);
1965 rt->state = STATE_SENDING;
1966 return write_status(s, pkt, "NetStream.Play.Start",
1969 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1971 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1972 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1976 ff_amf_write_string(&pp, "_result");
1977 ff_amf_write_number(&pp, seqnum);
1978 ff_amf_write_null(&pp);
1979 if (!strcmp(command, "createStream")) {
1981 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1982 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1983 ff_amf_write_number(&pp, rt->nb_streamid);
1984 /* By now we don't control which streams are removed in
1985 * deleteStream. There is no stream creation control
1986 * if a client creates more than 2^32 - 2 streams. */
1989 spkt.size = pp - spkt.data;
1990 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1991 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1992 ff_rtmp_packet_destroy(&spkt);
1997 * Read the AMF_NUMBER response ("_result") to a function call
1998 * (e.g. createStream()). This response should be made up of the AMF_STRING
1999 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2000 * successful response, we will return set the value to number (otherwise number
2001 * will not be changed).
2003 * @return 0 if reading the value succeeds, negative value otherwiss
2005 static int read_number_result(RTMPPacket *pkt, double *number)
2007 // We only need to fit "_result" in this.
2008 uint8_t strbuffer[8];
2013 bytestream2_init(&gbc, pkt->data, pkt->size);
2015 // Value 1/4: "_result" as AMF_STRING
2016 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2017 return AVERROR_INVALIDDATA;
2018 if (strcmp(strbuffer, "_result"))
2019 return AVERROR_INVALIDDATA;
2020 // Value 2/4: The callee reference number
2021 if (ff_amf_read_number(&gbc, &numbuffer))
2022 return AVERROR_INVALIDDATA;
2024 if (ff_amf_read_null(&gbc))
2025 return AVERROR_INVALIDDATA;
2026 // Value 4/4: The resonse as AMF_NUMBER
2027 if (ff_amf_read_number(&gbc, &numbuffer))
2028 return AVERROR_INVALIDDATA;
2030 *number = numbuffer;
2035 static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
2037 RTMPContext *rt = s->priv_data;
2038 char *tracked_method = NULL;
2041 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2044 if (!tracked_method) {
2045 /* Ignore this reply when the current method is not tracked. */
2049 if (!strcmp(tracked_method, "connect")) {
2050 if (!rt->is_input) {
2051 if ((ret = gen_release_stream(s, rt)) < 0)
2054 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2057 if ((ret = gen_server_bw(s, rt)) < 0)
2061 if ((ret = gen_create_stream(s, rt)) < 0)
2065 /* Send the FCSubscribe command when the name of live
2066 * stream is defined by the user or if it's a live stream. */
2067 if (rt->subscribe) {
2068 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2070 } else if (rt->live == -1) {
2071 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2075 } else if (!strcmp(tracked_method, "createStream")) {
2077 if (read_number_result(pkt, &stream_id)) {
2078 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2080 rt->stream_id = stream_id;
2083 if (!rt->is_input) {
2084 if ((ret = gen_publish(s, rt)) < 0)
2087 if (rt->live != -1) {
2088 if ((ret = gen_get_stream_length(s, rt)) < 0)
2091 if ((ret = gen_play(s, rt)) < 0)
2093 if ((ret = gen_buffer_time(s, rt)) < 0)
2096 } else if (!strcmp(tracked_method, "getStreamLength")) {
2097 if (read_number_result(pkt, &rt->duration)) {
2098 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2103 av_free(tracked_method);
2107 static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
2109 RTMPContext *rt = s->priv_data;
2110 const uint8_t *data_end = pkt->data + pkt->size;
2111 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2112 uint8_t tmpstr[256];
2115 for (i = 0; i < 2; i++) {
2116 t = ff_amf_tag_size(ptr, data_end);
2122 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2123 if (!t && !strcmp(tmpstr, "error")) {
2124 t = ff_amf_get_field_value(ptr, data_end,
2125 "description", tmpstr, sizeof(tmpstr));
2126 if (t || !tmpstr[0])
2127 t = ff_amf_get_field_value(ptr, data_end, "code",
2128 tmpstr, sizeof(tmpstr));
2130 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2134 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2135 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2136 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2137 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2138 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2139 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2144 static int handle_invoke(URLContext *s, RTMPPacket *pkt)
2146 RTMPContext *rt = s->priv_data;
2149 //TODO: check for the messages sent for wrong state?
2150 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2151 if ((ret = handle_invoke_error(s, pkt)) < 0)
2153 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2154 if ((ret = handle_invoke_result(s, pkt)) < 0)
2156 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2157 if ((ret = handle_invoke_status(s, pkt)) < 0)
2159 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2160 if ((ret = gen_check_bw(s, rt)) < 0)
2162 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2163 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2164 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2165 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2166 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2167 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2168 if ((ret = send_invoke_response(s, pkt)) < 0)
2175 static int update_offset(RTMPContext *rt, int size)
2179 // generate packet header and put data into buffer for FLV demuxer
2180 if (rt->flv_off < rt->flv_size) {
2181 // There is old unread data in the buffer, thus append at the end
2182 old_flv_size = rt->flv_size;
2183 rt->flv_size += size;
2185 // All data has been read, write the new data at the start of the buffer
2187 rt->flv_size = size;
2191 return old_flv_size;
2194 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2196 int old_flv_size, ret;
2198 const uint8_t *data = pkt->data + skip;
2199 const int size = pkt->size - skip;
2200 uint32_t ts = pkt->timestamp;
2202 if (pkt->type == RTMP_PT_AUDIO) {
2204 } else if (pkt->type == RTMP_PT_VIDEO) {
2208 old_flv_size = update_offset(rt, size + 15);
2210 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2211 rt->flv_size = rt->flv_off = 0;
2214 bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2215 bytestream2_skip_p(&pbc, old_flv_size);
2216 bytestream2_put_byte(&pbc, pkt->type);
2217 bytestream2_put_be24(&pbc, size);
2218 bytestream2_put_be24(&pbc, ts);
2219 bytestream2_put_byte(&pbc, ts >> 24);
2220 bytestream2_put_be24(&pbc, 0);
2221 bytestream2_put_buffer(&pbc, data, size);
2222 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2227 static int handle_notify(URLContext *s, RTMPPacket *pkt)
2229 RTMPContext *rt = s->priv_data;
2230 uint8_t commandbuffer[64];
2231 char statusmsg[128];
2232 int stringlen, ret, skip = 0;
2235 bytestream2_init(&gbc, pkt->data, pkt->size);
2236 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2238 return AVERROR_INVALIDDATA;
2240 if (!strcmp(commandbuffer, "onMetaData")) {
2241 // metadata properties should be stored in a mixed array
2242 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2243 // We have found a metaData Array so flv can determine the streams
2245 rt->received_metadata = 1;
2246 // skip 32-bit max array index
2247 bytestream2_skip(&gbc, 4);
2248 while (bytestream2_get_bytes_left(&gbc) > 3) {
2249 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2251 return AVERROR_INVALIDDATA;
2252 // We do not care about the content of the property (yet).
2253 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2255 return AVERROR_INVALIDDATA;
2256 bytestream2_skip(&gbc, stringlen);
2258 // The presence of the following properties indicates that the
2259 // respective streams are present.
2260 if (!strcmp(statusmsg, "videocodecid")) {
2263 if (!strcmp(statusmsg, "audiocodecid")) {
2267 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2268 return AVERROR_INVALIDDATA;
2272 // Skip the @setDataFrame string and validate it is a notification
2273 if (!strcmp(commandbuffer, "@setDataFrame")) {
2274 skip = gbc.buffer - pkt->data;
2275 ret = ff_amf_read_string(&gbc, statusmsg,
2276 sizeof(statusmsg), &stringlen);
2278 return AVERROR_INVALIDDATA;
2281 return append_flv_data(rt, pkt, skip);
2285 * Parse received packet and possibly perform some action depending on
2286 * the packet contents.
2287 * @return 0 for no errors, negative values for serious errors which prevent
2288 * further communications, positive values for uncritical errors
2290 static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2295 ff_rtmp_packet_dump(s, pkt);
2298 switch (pkt->type) {
2299 case RTMP_PT_BYTES_READ:
2300 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2302 case RTMP_PT_CHUNK_SIZE:
2303 if ((ret = handle_chunk_size(s, pkt)) < 0)
2307 if ((ret = handle_ping(s, pkt)) < 0)
2310 case RTMP_PT_CLIENT_BW:
2311 if ((ret = handle_client_bw(s, pkt)) < 0)
2314 case RTMP_PT_SERVER_BW:
2315 if ((ret = handle_server_bw(s, pkt)) < 0)
2318 case RTMP_PT_INVOKE:
2319 if ((ret = handle_invoke(s, pkt)) < 0)
2324 case RTMP_PT_METADATA:
2325 case RTMP_PT_NOTIFY:
2326 /* Audio, Video and Metadata packets are parsed in get_packet() */
2329 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2335 static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
2337 int ret, old_flv_size, type;
2338 const uint8_t *next;
2341 uint32_t ts, cts, pts = 0;
2343 old_flv_size = update_offset(rt, pkt->size);
2345 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2346 rt->flv_size = rt->flv_off = 0;
2351 p = rt->flv_data + old_flv_size;
2353 /* copy data while rewriting timestamps */
2354 ts = pkt->timestamp;
2356 while (next - pkt->data < pkt->size - RTMP_HEADER) {
2357 type = bytestream_get_byte(&next);
2358 size = bytestream_get_be24(&next);
2359 cts = bytestream_get_be24(&next);
2360 cts |= bytestream_get_byte(&next) << 24;
2365 if (size + 3 + 4 > pkt->data + pkt->size - next)
2367 bytestream_put_byte(&p, type);
2368 bytestream_put_be24(&p, size);
2369 bytestream_put_be24(&p, ts);
2370 bytestream_put_byte(&p, ts >> 24);
2371 memcpy(p, next, size + 3 + 4);
2373 bytestream_put_be32(&p, size + RTMP_HEADER);
2374 next += size + 3 + 4;
2376 if (p != rt->flv_data + rt->flv_size) {
2377 av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2378 "RTMP_PT_METADATA packet\n");
2379 rt->flv_size = p - rt->flv_data;
2386 * Interact with the server by receiving and sending RTMP packets until
2387 * there is some significant data (media data or expected status notification).
2389 * @param s reading context
2390 * @param for_header non-zero value tells function to work until it
2391 * gets notification from the server that playing has been started,
2392 * otherwise function will work until some media data is received (or
2394 * @return 0 for successful operation, negative value in case of error
2396 static int get_packet(URLContext *s, int for_header)
2398 RTMPContext *rt = s->priv_data;
2401 if (rt->state == STATE_STOPPED)
2405 RTMPPacket rpkt = { 0 };
2406 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2407 rt->in_chunk_size, &rt->prev_pkt[0],
2408 &rt->nb_prev_pkt[0])) <= 0) {
2410 return AVERROR(EAGAIN);
2412 return AVERROR(EIO);
2416 // Track timestamp for later use
2417 rt->last_timestamp = rpkt.timestamp;
2419 rt->bytes_read += ret;
2420 if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2421 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2422 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2424 rt->last_bytes_read = rt->bytes_read;
2427 ret = rtmp_parse_result(s, rt, &rpkt);
2429 // At this point we must check if we are in the seek state and continue
2430 // with the next packet. handle_invoke will get us out of this state
2431 // when the right message is encountered
2432 if (rt->state == STATE_SEEKING) {
2433 ff_rtmp_packet_destroy(&rpkt);
2434 // We continue, let the natural flow of things happen:
2435 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2439 if (ret < 0) {//serious error in current packet
2440 ff_rtmp_packet_destroy(&rpkt);
2443 if (rt->do_reconnect && for_header) {
2444 ff_rtmp_packet_destroy(&rpkt);
2447 if (rt->state == STATE_STOPPED) {
2448 ff_rtmp_packet_destroy(&rpkt);
2451 if (for_header && (rt->state == STATE_PLAYING ||
2452 rt->state == STATE_PUBLISHING ||
2453 rt->state == STATE_SENDING ||
2454 rt->state == STATE_RECEIVING)) {
2455 ff_rtmp_packet_destroy(&rpkt);
2458 if (!rpkt.size || !rt->is_input) {
2459 ff_rtmp_packet_destroy(&rpkt);
2462 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2463 ret = append_flv_data(rt, &rpkt, 0);
2464 ff_rtmp_packet_destroy(&rpkt);
2466 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2467 ret = handle_notify(s, &rpkt);
2468 ff_rtmp_packet_destroy(&rpkt);
2470 } else if (rpkt.type == RTMP_PT_METADATA) {
2471 ret = handle_metadata(rt, &rpkt);
2472 ff_rtmp_packet_destroy(&rpkt);
2475 ff_rtmp_packet_destroy(&rpkt);
2479 static int rtmp_close(URLContext *h)
2481 RTMPContext *rt = h->priv_data;
2484 if (!rt->is_input) {
2485 rt->flv_data = NULL;
2486 if (rt->out_pkt.size)
2487 ff_rtmp_packet_destroy(&rt->out_pkt);
2488 if (rt->state > STATE_FCPUBLISH)
2489 ret = gen_fcunpublish_stream(h, rt);
2491 if (rt->state > STATE_HANDSHAKED)
2492 ret = gen_delete_stream(h, rt);
2493 for (i = 0; i < 2; i++) {
2494 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2495 ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2496 av_freep(&rt->prev_pkt[i]);
2499 free_tracked_methods(rt);
2500 av_freep(&rt->flv_data);
2501 ffurl_close(rt->stream);
2506 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2507 * demuxer about the duration of the stream.
2509 * This should only be done if there was no real onMetadata packet sent by the
2510 * server at the start of the stream and if we were able to retrieve a valid
2511 * duration via a getStreamLength call.
2513 * @return 0 for successful operation, negative value in case of error
2515 static int inject_fake_duration_metadata(RTMPContext *rt)
2517 // We need to insert the metdata packet directly after the FLV
2518 // header, i.e. we need to move all other already read data by the
2519 // size of our fake metadata packet.
2522 // Keep old flv_data pointer
2523 uint8_t* old_flv_data = rt->flv_data;
2524 // Allocate a new flv_data pointer with enough space for the additional package
2525 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2526 rt->flv_data = old_flv_data;
2527 return AVERROR(ENOMEM);
2531 memcpy(rt->flv_data, old_flv_data, 13);
2532 // Copy remaining packets
2533 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2534 // Increase the size by the injected packet
2536 // Delete the old FLV data
2537 av_freep(&old_flv_data);
2539 p = rt->flv_data + 13;
2540 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2541 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2542 bytestream_put_be24(&p, 0); // timestamp
2543 bytestream_put_be32(&p, 0); // reserved
2545 // first event name as a string
2546 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2547 // "onMetaData" as AMF string
2548 bytestream_put_be16(&p, 10);
2549 bytestream_put_buffer(&p, "onMetaData", 10);
2551 // mixed array (hash) with size and string/type/data tuples
2552 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2553 bytestream_put_be32(&p, 1); // metadata_count
2555 // "duration" as AMF string
2556 bytestream_put_be16(&p, 8);
2557 bytestream_put_buffer(&p, "duration", 8);
2558 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2559 bytestream_put_be64(&p, av_double2int(rt->duration));
2562 bytestream_put_be16(&p, 0); // Empty string
2563 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2564 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2570 * Open RTMP connection and verify that the stream can be played.
2572 * URL syntax: rtmp://server[:port][/app][/playpath]
2573 * where 'app' is first one or two directories in the path
2574 * (e.g. /ondemand/, /flash/live/, etc.)
2575 * and 'playpath' is a file name (the rest of the path,
2576 * may be prefixed with "mp4:")
2578 static int rtmp_open(URLContext *s, const char *uri, int flags)
2580 RTMPContext *rt = s->priv_data;
2581 char proto[8], hostname[256], path[1024], auth[100], *fname;
2582 char *old_app, *qmark, *n, fname_buffer[1024];
2585 AVDictionary *opts = NULL;
2588 if (rt->listen_timeout > 0)
2591 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2593 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2594 hostname, sizeof(hostname), &port,
2595 path, sizeof(path), s->filename);
2597 n = strchr(path, ' ');
2599 av_log(s, AV_LOG_WARNING,
2600 "Detected librtmp style URL parameters, these aren't supported "
2601 "by the libavformat internal RTMP handler currently enabled. "
2602 "See the documentation for the correct way to pass parameters.\n");
2603 *n = '\0'; // Trim not supported part
2607 char *ptr = strchr(auth, ':');
2610 av_strlcpy(rt->username, auth, sizeof(rt->username));
2611 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2615 if (rt->listen && strcmp(proto, "rtmp")) {
2616 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2618 return AVERROR(EINVAL);
2620 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2621 if (!strcmp(proto, "rtmpts"))
2622 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2624 /* open the http tunneling connection */
2625 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2626 } else if (!strcmp(proto, "rtmps")) {
2627 /* open the tls connection */
2629 port = RTMPS_DEFAULT_PORT;
2630 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2631 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2632 if (!strcmp(proto, "rtmpte"))
2633 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2635 /* open the encrypted connection */
2636 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2639 /* open the tcp connection */
2641 port = RTMP_DEFAULT_PORT;
2643 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2644 "?listen&listen_timeout=%d",
2645 rt->listen_timeout * 1000);
2647 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2651 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2652 &s->interrupt_callback, &opts,
2653 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2654 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2658 if (rt->swfverify) {
2659 if ((ret = rtmp_calc_swfhash(s)) < 0)
2663 rt->state = STATE_START;
2664 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2666 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2669 rt->out_chunk_size = 128;
2670 rt->in_chunk_size = 128; // Probably overwritten later
2671 rt->state = STATE_HANDSHAKED;
2673 // Keep the application name when it has been defined by the user.
2676 rt->app = av_malloc(APP_MAX_LENGTH);
2678 ret = AVERROR(ENOMEM);
2682 //extract "app" part from path
2683 qmark = strchr(path, '?');
2684 if (qmark && strstr(qmark, "slist=")) {
2686 // After slist we have the playpath, the full path is used as app
2687 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2688 fname = strstr(path, "slist=") + 6;
2689 // Strip any further query parameters from fname
2690 amp = strchr(fname, '&');
2692 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2693 sizeof(fname_buffer)));
2694 fname = fname_buffer;
2696 } else if (!strncmp(path, "/ondemand/", 10)) {
2698 memcpy(rt->app, "ondemand", 9);
2700 char *next = *path ? path + 1 : path;
2701 char *p = strchr(next, '/');
2704 // If name of application has been defined by the user, assume that
2705 // playpath is provided in the URL
2709 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2712 // make sure we do not mismatch a playpath for an application instance
2713 char *c = strchr(p + 1, ':');
2714 fname = strchr(p + 1, '/');
2715 if (!fname || (c && c < fname)) {
2717 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2720 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2726 // The name of application has been defined by the user, override it.
2727 if (strlen(old_app) >= APP_MAX_LENGTH) {
2728 ret = AVERROR(EINVAL);
2735 if (!rt->playpath) {
2736 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2737 if (!rt->playpath) {
2738 ret = AVERROR(ENOMEM);
2743 int len = strlen(fname);
2744 if (!strchr(fname, ':') && len >= 4 &&
2745 (!strcmp(fname + len - 4, ".f4v") ||
2746 !strcmp(fname + len - 4, ".mp4"))) {
2747 memcpy(rt->playpath, "mp4:", 5);
2749 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2750 fname[len - 4] = '\0';
2751 rt->playpath[0] = 0;
2753 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
2755 rt->playpath[0] = '\0';
2760 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
2762 ret = AVERROR(ENOMEM);
2765 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2766 port, "/%s", rt->app);
2769 if (!rt->flashver) {
2770 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
2771 if (!rt->flashver) {
2772 ret = AVERROR(ENOMEM);
2776 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2777 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2778 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2780 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2781 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2785 rt->client_report_size = 1048576;
2789 rt->received_metadata = 0;
2790 rt->last_bytes_read = 0;
2791 rt->server_bw = 2500000;
2794 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2795 proto, path, rt->app, rt->playpath);
2797 if ((ret = gen_connect(s, rt)) < 0)
2800 if ((ret = read_connect(s, s->priv_data)) < 0)
2805 ret = get_packet(s, 1);
2806 } while (ret == AVERROR(EAGAIN));
2810 if (rt->do_reconnect) {
2812 ffurl_close(rt->stream);
2814 rt->do_reconnect = 0;
2816 for (i = 0; i < 2; i++)
2817 memset(rt->prev_pkt[i], 0,
2818 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2819 free_tracked_methods(rt);
2824 // generate FLV header for demuxer
2826 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2829 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2831 // Read packets until we reach the first A/V packet or read metadata.
2832 // If there was a metadata package in front of the A/V packets, we can
2833 // build the FLV header from this. If we do not receive any metadata,
2834 // the FLV decoder will allocate the needed streams when their first
2835 // audio or video packet arrives.
2836 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2837 if ((ret = get_packet(s, 0)) < 0)
2841 // Either after we have read the metadata or (if there is none) the
2842 // first packet of an A/V stream, we have a better knowledge about the
2843 // streams, so set the FLV header accordingly.
2844 if (rt->has_audio) {
2845 rt->flv_data[4] |= FLV_HEADER_FLAG_HASAUDIO;
2847 if (rt->has_video) {
2848 rt->flv_data[4] |= FLV_HEADER_FLAG_HASVIDEO;
2851 // If we received the first packet of an A/V stream and no metadata but
2852 // the server returned a valid duration, create a fake metadata packet
2853 // to inform the FLV decoder about the duration.
2854 if (!rt->received_metadata && rt->duration > 0) {
2855 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2860 rt->flv_data = NULL;
2862 rt->skip_bytes = 13;
2865 s->max_packet_size = rt->stream->max_packet_size;
2870 av_dict_free(&opts);
2875 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2877 RTMPContext *rt = s->priv_data;
2878 int orig_size = size;
2882 int data_left = rt->flv_size - rt->flv_off;
2884 if (data_left >= size) {
2885 memcpy(buf, rt->flv_data + rt->flv_off, size);
2886 rt->flv_off += size;
2889 if (data_left > 0) {
2890 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2893 rt->flv_off = rt->flv_size;
2896 if ((ret = get_packet(s, 0)) < 0)
2902 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2905 RTMPContext *rt = s->priv_data;
2907 av_log(s, AV_LOG_DEBUG,
2908 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2909 stream_index, timestamp, flags);
2910 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2911 av_log(s, AV_LOG_ERROR,
2912 "Unable to send seek command on stream index %d at timestamp "
2913 "%"PRId64" with flags %08x\n",
2914 stream_index, timestamp, flags);
2917 rt->flv_off = rt->flv_size;
2918 rt->state = STATE_SEEKING;
2922 static int rtmp_pause(URLContext *s, int pause)
2924 RTMPContext *rt = s->priv_data;
2926 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2927 rt->last_timestamp);
2928 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2929 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2930 rt->last_timestamp);
2936 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2938 RTMPContext *rt = s->priv_data;
2939 int size_temp = size;
2940 int pktsize, pkttype, copy;
2942 const uint8_t *buf_temp = buf;
2947 if (rt->skip_bytes) {
2948 int skip = FFMIN(rt->skip_bytes, size_temp);
2951 rt->skip_bytes -= skip;
2955 if (rt->flv_header_bytes < RTMP_HEADER) {
2956 const uint8_t *header = rt->flv_header;
2957 int channel = RTMP_AUDIO_CHANNEL;
2959 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2960 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2961 rt->flv_header_bytes += copy;
2963 if (rt->flv_header_bytes < RTMP_HEADER)
2966 pkttype = bytestream_get_byte(&header);
2967 pktsize = bytestream_get_be24(&header);
2968 ts = bytestream_get_be24(&header);
2969 ts |= bytestream_get_byte(&header) << 24;
2970 bytestream_get_be24(&header);
2971 rt->flv_size = pktsize;
2973 if (pkttype == RTMP_PT_VIDEO)
2974 channel = RTMP_VIDEO_CHANNEL;
2976 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2977 pkttype == RTMP_PT_NOTIFY) {
2978 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2979 &rt->nb_prev_pkt[1],
2982 // Force sending a full 12 bytes header by clearing the
2983 // channel id, to make it not match a potential earlier
2984 // packet in the same channel.
2985 rt->prev_pkt[1][channel].channel_id = 0;
2988 //this can be a big packet, it's better to send it right here
2989 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2990 pkttype, ts, pktsize)) < 0)
2993 rt->out_pkt.extra = rt->stream_id;
2994 rt->flv_data = rt->out_pkt.data;
2997 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
2998 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
2999 rt->flv_off += copy;
3002 if (rt->flv_off == rt->flv_size) {
3005 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3006 // For onMetaData and |RtmpSampleAccess packets, we want
3007 // @setDataFrame prepended to the packet before it gets sent.
3008 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3010 uint8_t commandbuffer[64];
3014 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3015 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3017 if (!strcmp(commandbuffer, "onMetaData") ||
3018 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3020 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3021 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3024 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3025 rt->out_pkt.size += 16;
3026 ptr = rt->out_pkt.data;
3027 ff_amf_write_string(&ptr, "@setDataFrame");
3032 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3036 rt->flv_header_bytes = 0;
3037 rt->flv_nb_packets++;
3039 } while (buf_temp - buf < size);
3041 if (rt->flv_nb_packets < rt->flush_interval)
3043 rt->flv_nb_packets = 0;
3045 /* set stream into nonblocking mode */
3046 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
3048 /* try to read one byte from the stream */
3049 ret = ffurl_read(rt->stream, &c, 1);
3051 /* switch the stream back into blocking mode */
3052 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3054 if (ret == AVERROR(EAGAIN)) {
3055 /* no incoming data to handle */
3057 } else if (ret < 0) {
3059 } else if (ret == 1) {
3060 RTMPPacket rpkt = { 0 };
3062 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3065 &rt->nb_prev_pkt[0], c)) <= 0)
3068 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3071 ff_rtmp_packet_destroy(&rpkt);
3077 #define OFFSET(x) offsetof(RTMPContext, x)
3078 #define DEC AV_OPT_FLAG_DECODING_PARAM
3079 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3081 static const AVOption rtmp_options[] = {
3082 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3083 {"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},
3084 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3085 {"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},
3086 {"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},
3087 {"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"},
3088 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3089 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3090 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3091 {"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},
3092 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3093 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3094 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3095 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3096 {"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},
3097 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3098 {"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},
3099 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3100 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3101 {"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" },
3105 #define RTMP_PROTOCOL(flavor) \
3106 static const AVClass flavor##_class = { \
3107 .class_name = #flavor, \
3108 .item_name = av_default_item_name, \
3109 .option = rtmp_options, \
3110 .version = LIBAVUTIL_VERSION_INT, \
3113 const URLProtocol ff_##flavor##_protocol = { \
3115 .url_open = rtmp_open, \
3116 .url_read = rtmp_read, \
3117 .url_read_seek = rtmp_seek, \
3118 .url_read_pause = rtmp_pause, \
3119 .url_write = rtmp_write, \
3120 .url_close = rtmp_close, \
3121 .priv_data_size = sizeof(RTMPContext), \
3122 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3123 .priv_data_class= &flavor##_class, \
3128 RTMP_PROTOCOL(rtmpe)
3129 RTMP_PROTOCOL(rtmps)
3130 RTMP_PROTOCOL(rtmpt)
3131 RTMP_PROTOCOL(rtmpte)
3132 RTMP_PROTOCOL(rtmpts)