FFmpeg
Loading...
Searching...
No Matches
rtmpproto.c
Go to the documentation of this file.
1/*
2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
4 *
5 * This file is part of FFmpeg.
6 *
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.
11 *
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.
16 *
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
20 */
21
22/**
23 * @file
24 * RTMP protocol
25 */
26
27#include "config_components.h"
28
30#include "libavutil/avstring.h"
31#include "libavutil/base64.h"
32#include "libavutil/intfloat.h"
33#include "libavutil/lfg.h"
34#include "libavutil/md5.h"
35#include "libavutil/mem.h"
36#include "libavutil/opt.h"
38#include "avformat.h"
39#include "internal.h"
40
41#include "network.h"
42
43#include "flv.h"
44#include "rtmp.h"
45#include "rtmpcrypt.h"
46#include "rtmppkt.h"
47#include "url.h"
48#include "version.h"
49
50#if CONFIG_ZLIB
51#include <zlib.h>
52#endif
53
54#define APP_MAX_LENGTH 1024
55#define TCURL_MAX_LENGTH 1024
56#define FLASHVER_MAX_LENGTH 64
57#define RTMP_PKTDATA_DEFAULT_SIZE 4096
58#define RTMP_HEADER 11
59
60/** RTMP protocol handler state */
61typedef enum {
62 STATE_START, ///< client has not done anything yet
63 STATE_HANDSHAKED, ///< client has performed handshake
64 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
65 STATE_PLAYING, ///< client has started receiving multimedia data from server
66 STATE_SEEKING, ///< client has started the seek operation. Back on STATE_PLAYING when the time comes
67 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
68 STATE_RECEIVING, ///< received a publish command (for input)
69 STATE_SENDING, ///< received a play command (for output)
70 STATE_STOPPED, ///< the broadcast has been stopped
72
73typedef struct TrackedMethod {
74 char *name;
75 int id;
77
78/** protocol handler context */
79typedef struct RTMPContext {
80 const AVClass *class;
81 URLContext* stream; ///< TCP stream used in interactions with RTMP server
82 RTMPPacket *prev_pkt[2]; ///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
83 int nb_prev_pkt[2]; ///< number of elements in prev_pkt
84 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
85 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
86 int is_input; ///< input/output flag
87 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
88 int live; ///< 0: recorded, -1: live, -2: both
89 char *app; ///< name of application
90 char *conn; ///< append arbitrary AMF data to the Connect message
91 ClientState state; ///< current state
92 int stream_id; ///< ID assigned by the server for the stream
93 uint8_t* flv_data; ///< buffer with data for demuxer
94 int flv_size; ///< current buffer size
95 int flv_off; ///< number of bytes read from current buffer
96 int flv_nb_packets; ///< number of flv packets published
97 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
98 uint32_t receive_report_size; ///< number of bytes after which we should report the number of received bytes to the peer
99 uint64_t bytes_read; ///< number of bytes read from server
100 uint64_t last_bytes_read; ///< number of bytes read last reported to server
101 uint32_t last_timestamp; ///< last timestamp received in a packet
102 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
103 int has_audio; ///< presence of audio data
104 int has_video; ///< presence of video data
105 int received_metadata; ///< Indicates if we have received metadata about the streams
106 uint8_t flv_header[RTMP_HEADER]; ///< partial incoming flv packet header
107 int flv_header_bytes; ///< number of initialized bytes in flv_header
108 int nb_invokes; ///< keeps track of invoke messages
109 char* tcurl; ///< url of the target stream
110 char* flashver; ///< version of the flash plugin
111 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
112 int swfhash_len; ///< length of the SHA256 hash
113 int swfsize; ///< size of the decompressed SWF file
114 char* swfurl; ///< url of the swf player
115 char* swfverify; ///< URL to player swf file, compute hash/size automatically
116 char swfverification[42]; ///< hash of the SWF verification
117 char* pageurl; ///< url of the web page
118 char* subscribe; ///< name of live stream to subscribe
119 int max_sent_unacked; ///< max unacked sent bytes
120 int client_buffer_time; ///< client buffer time in ms
121 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
122 int encrypted; ///< use an encrypted connection (RTMPE only)
123 TrackedMethod*tracked_methods; ///< tracked methods buffer
124 int nb_tracked_methods; ///< number of tracked methods
125 int tracked_methods_size; ///< size of the tracked methods buffer
126 int listen; ///< listen mode flag
127 int listen_timeout; ///< listen timeout to wait for new connections
128 int nb_streamid; ///< The next stream id to return on createStream calls
129 double duration; ///< Duration of the stream in seconds as returned by the server (only valid if non-zero)
130 int tcp_nodelay; ///< Use TCP_NODELAY to disable Nagle's algorithm if set to 1
131 char *enhanced_codecs; ///< codec list in enhanced rtmp
132 char username[50];
133 char password[50];
134 char auth_params[500];
138
139#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
140/** Client key used for digest signing */
141static const uint8_t rtmp_player_key[] = {
142 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
143 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
144
145 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
146 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
147 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
148};
149
150#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
151/** Key used for RTMP server digest signing */
152static const uint8_t rtmp_server_key[] = {
153 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
154 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
155 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
156
157 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
158 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
159 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
160};
161
165
166static size_t zstrlen(const char *c)
167{
168 if(c)
169 return strlen(c);
170 return 0;
171}
172
173static int add_tracked_method(RTMPContext *rt, const char *name, int id)
174{
175 int err;
176
177 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
178 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
180 sizeof(*rt->tracked_methods))) < 0) {
181 rt->nb_tracked_methods = 0;
182 rt->tracked_methods_size = 0;
183 return err;
184 }
185 }
186
189 return AVERROR(ENOMEM);
191 rt->nb_tracked_methods++;
192
193 return 0;
194}
195
197{
198 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
199 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
200 rt->nb_tracked_methods--;
201}
202
204 char **tracked_method)
205{
206 RTMPContext *rt = s->priv_data;
207 GetByteContext gbc;
208 double pkt_id;
209 int ret;
210 int i;
211
212 bytestream2_init(&gbc, pkt->data + offset, pkt->size - offset);
213 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
214 return ret;
215
216 for (i = 0; i < rt->nb_tracked_methods; i++) {
217 if (rt->tracked_methods[i].id != pkt_id)
218 continue;
219
220 *tracked_method = rt->tracked_methods[i].name;
222 break;
223 }
224
225 return 0;
226}
227
229{
230 int i;
231
232 for (i = 0; i < rt->nb_tracked_methods; i ++)
235 rt->tracked_methods_size = 0;
236 rt->nb_tracked_methods = 0;
237}
238
239static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
240{
241 int ret;
242
243 if (pkt->type == RTMP_PT_INVOKE && track) {
244 GetByteContext gbc;
245 char name[128];
246 double pkt_id;
247 int len;
248
249 bytestream2_init(&gbc, pkt->data, pkt->size);
250 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
251 goto fail;
252
253 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
254 goto fail;
255
256 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
257 goto fail;
258 }
259
261 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
262fail:
264 return ret;
265}
266
267static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
268{
269 char *field, *value;
270 char type;
271
272 /* The type must be B for Boolean, N for number, S for string, O for
273 * object, or Z for null. For Booleans the data must be either 0 or 1 for
274 * FALSE or TRUE, respectively. Likewise for Objects the data must be
275 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
276 * may be named, by prefixing the type with 'N' and specifying the name
277 * before the value (ie. NB:myFlag:1). This option may be used multiple times
278 * to construct arbitrary AMF sequences. */
279 if (param[0] && param[1] == ':') {
280 type = param[0];
281 value = param + 2;
282 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
283 type = param[1];
284 field = param + 3;
285 value = strchr(field, ':');
286 if (!value)
287 goto fail;
288 *value = '\0';
289 value++;
290
291 ff_amf_write_field_name(p, field);
292 } else {
293 goto fail;
294 }
295
296 switch (type) {
297 case 'B':
298 ff_amf_write_bool(p, value[0] != '0');
299 break;
300 case 'S':
302 break;
303 case 'N':
305 break;
306 case 'Z':
308 break;
309 case 'O':
310 if (value[0] != '0')
312 else
314 break;
315 default:
316 goto fail;
317 break;
318 }
319
320 return 0;
321
322fail:
323 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
324 return AVERROR(EINVAL);
325}
326
327/**
328 * Generate 'connect' call and send it to the server.
329 */
331{
333 uint8_t *p;
334 int ret;
335
337 0, 4096 + APP_MAX_LENGTH
338 + strlen(rt->auth_params) + strlen(rt->flashver)
339 + zstrlen(rt->enhanced_codecs)/5*7
340 + zstrlen(rt->swfurl)
341 + zstrlen(rt->swfverify)
342 + zstrlen(rt->tcurl)
343 + zstrlen(rt->auth_params)
344 + zstrlen(rt->pageurl)
345 + zstrlen(rt->conn)*3
346 )) < 0)
347 return ret;
348
349 p = pkt.data;
350
351 ff_amf_write_string(&p, "connect");
354 ff_amf_write_field_name(&p, "app");
356
357 if (rt->enhanced_codecs) {
358 uint32_t list_len = 0;
359 char *fourcc_data = rt->enhanced_codecs;
360 int fourcc_str_len = strlen(fourcc_data);
361
362 // check the string, fourcc + ',' + ... + end fourcc correct length should be (4+1)*n+4
363 if ((fourcc_str_len + 1) % 5 != 0) {
364 av_log(s, AV_LOG_ERROR, "Malformed rtmp_enhanched_codecs, "
365 "should be of the form hvc1[,av01][,vp09][,vvc1][,...]\n");
367 return AVERROR(EINVAL);
368 }
369
370 list_len = (fourcc_str_len + 1) / 5;
371 ff_amf_write_field_name(&p, "fourCcList");
372 ff_amf_write_array_start(&p, list_len);
373
374 while(fourcc_data - rt->enhanced_codecs < fourcc_str_len) {
375 unsigned char fourcc[5];
376 if (!strncmp(fourcc_data, "ac-3", 4) ||
377 !strncmp(fourcc_data, "av01", 4) ||
378 !strncmp(fourcc_data, "avc1", 4) ||
379 !strncmp(fourcc_data, "ec-3", 4) ||
380 !strncmp(fourcc_data, "fLaC", 4) ||
381 !strncmp(fourcc_data, "hvc1", 4) ||
382 !strncmp(fourcc_data, "vvc1", 4) ||
383 !strncmp(fourcc_data, ".mp3", 4) ||
384 !strncmp(fourcc_data, "mp4a", 4) ||
385 !strncmp(fourcc_data, "Opus", 4) ||
386 !strncmp(fourcc_data, "vp09", 4)) {
387 av_strlcpy(fourcc, fourcc_data, sizeof(fourcc));
389 } else {
390 av_log(s, AV_LOG_ERROR, "Unsupported codec fourcc, %.*s\n", 4, fourcc_data);
393 }
394
395 fourcc_data += 5;
396 }
397 }
398
399 if (!rt->is_input) {
400 ff_amf_write_field_name(&p, "type");
401 ff_amf_write_string(&p, "nonprivate");
402 }
403 ff_amf_write_field_name(&p, "flashVer");
405
406 if (rt->swfurl || rt->swfverify) {
407 ff_amf_write_field_name(&p, "swfUrl");
408 if (rt->swfurl)
410 else
412 }
413
414 ff_amf_write_field_name(&p, "tcUrl");
416 if (rt->is_input) {
417 ff_amf_write_field_name(&p, "fpad");
418 ff_amf_write_bool(&p, 0);
419 ff_amf_write_field_name(&p, "capabilities");
420 ff_amf_write_number(&p, 15.0);
421
422 /* Tell the server we support all the audio codecs except
423 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
424 * which are unused in the RTMP protocol implementation. */
425 ff_amf_write_field_name(&p, "audioCodecs");
426 ff_amf_write_number(&p, 4071.0);
427 ff_amf_write_field_name(&p, "videoCodecs");
428 ff_amf_write_number(&p, 252.0);
429 ff_amf_write_field_name(&p, "videoFunction");
430 ff_amf_write_number(&p, 1.0);
431
432 if (rt->pageurl) {
433 ff_amf_write_field_name(&p, "pageUrl");
435 }
436 }
438
439 if (rt->conn) {
440 char *param = rt->conn;
441
442 // Write arbitrary AMF data to the Connect message.
443 while (param) {
444 char *sep;
445 param += strspn(param, " ");
446 if (!*param)
447 break;
448 sep = strchr(param, ' ');
449 if (sep)
450 *sep = '\0';
451 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
452 // Invalid AMF parameter.
454 return ret;
455 }
456
457 if (sep)
458 param = sep + 1;
459 else
460 break;
461 }
462 }
463
464 pkt.size = p - pkt.data;
465
466 return rtmp_send_packet(rt, &pkt, 1);
467}
468
469
470#define RTMP_CTRL_ABORT_MESSAGE (2)
471
473{
474 RTMPPacket pkt = { 0 };
475 uint8_t *p;
476 const uint8_t *cp;
477 int ret;
478 char command[64];
479 int stringlen;
480 double seqnum;
481 uint8_t tmpstr[256];
482 GetByteContext gbc;
483
484 // handle RTMP Protocol Control Messages
485 for (;;) {
486 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
487 &rt->prev_pkt[0], &rt->nb_prev_pkt[0])) < 0)
488 return ret;
489#ifdef DEBUG
491#endif
492 if (pkt.type == RTMP_PT_CHUNK_SIZE) {
493 if ((ret = handle_chunk_size(s, &pkt)) < 0) {
495 return ret;
496 }
497 } else if (pkt.type == RTMP_CTRL_ABORT_MESSAGE) {
498 av_log(s, AV_LOG_ERROR, "received abort message\n");
500 return AVERROR_UNKNOWN;
501 } else if (pkt.type == RTMP_PT_BYTES_READ) {
502 av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
503 } else if (pkt.type == RTMP_PT_WINDOW_ACK_SIZE) {
504 if ((ret = handle_window_ack_size(s, &pkt)) < 0) {
506 return ret;
507 }
508 } else if (pkt.type == RTMP_PT_SET_PEER_BW) {
509 if ((ret = handle_set_peer_bw(s, &pkt)) < 0) {
511 return ret;
512 }
513 } else if (pkt.type == RTMP_PT_INVOKE) {
514 // received RTMP Command Message
515 break;
516 } else {
517 av_log(s, AV_LOG_ERROR, "Unknown control message type (%d)\n", pkt.type);
518 }
520 }
521
522 cp = pkt.data;
523 bytestream2_init(&gbc, cp, pkt.size);
524 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
525 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
527 return AVERROR_INVALIDDATA;
528 }
529 if (strcmp(command, "connect")) {
530 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
532 return AVERROR_INVALIDDATA;
533 }
534 ret = ff_amf_read_number(&gbc, &seqnum);
535 if (ret)
536 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
537 /* Here one could parse an AMF Object with data as flashVers and others. */
540 "app", tmpstr, sizeof(tmpstr));
541 if (ret)
542 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
543 if (!ret && strcmp(tmpstr, rt->app))
544 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
545 tmpstr, rt->app);
547
548 // Send Window Acknowledgement Size (as defined in specification)
550 RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
551 return ret;
552 p = pkt.data;
553 // Inform the peer about how often we want acknowledgements about what
554 // we send. (We don't check for the acknowledgements currently.)
555 bytestream_put_be32(&p, rt->max_sent_unacked);
556 pkt.size = p - pkt.data;
558 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
560 if (ret < 0)
561 return ret;
562 // Set Peer Bandwidth
564 RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
565 return ret;
566 p = pkt.data;
567 // Tell the peer to only send this many bytes unless it gets acknowledgements.
568 // This could be any arbitrary value we want here.
569 bytestream_put_be32(&p, rt->max_sent_unacked);
570 bytestream_put_byte(&p, 2); // dynamic
571 pkt.size = p - pkt.data;
573 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
575 if (ret < 0)
576 return ret;
577
578 // User control
580 RTMP_PT_USER_CONTROL, 0, 6)) < 0)
581 return ret;
582
583 p = pkt.data;
584 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
585 bytestream_put_be32(&p, 0); // Stream 0
587 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
589 if (ret < 0)
590 return ret;
591
592 // Chunk size
594 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
595 return ret;
596
597 p = pkt.data;
598 bytestream_put_be32(&p, rt->out_chunk_size);
600 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
602 if (ret < 0)
603 return ret;
604
605 // Send _result NetConnection.Connect.Success to connect
609 return ret;
610
611 p = pkt.data;
612 ff_amf_write_string(&p, "_result");
613 ff_amf_write_number(&p, seqnum);
614
616 ff_amf_write_field_name(&p, "fmsVer");
617 ff_amf_write_string(&p, "FMS/3,0,1,123");
618 ff_amf_write_field_name(&p, "capabilities");
619 ff_amf_write_number(&p, 31);
621
623 ff_amf_write_field_name(&p, "level");
624 ff_amf_write_string(&p, "status");
625 ff_amf_write_field_name(&p, "code");
626 ff_amf_write_string(&p, "NetConnection.Connect.Success");
627 ff_amf_write_field_name(&p, "description");
628 ff_amf_write_string(&p, "Connection succeeded.");
629 ff_amf_write_field_name(&p, "objectEncoding");
630 ff_amf_write_number(&p, 0);
632
633 pkt.size = p - pkt.data;
635 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
637 if (ret < 0)
638 return ret;
639
641 RTMP_PT_INVOKE, 0, 30)) < 0)
642 return ret;
643 p = pkt.data;
644 ff_amf_write_string(&p, "onBWDone");
645 ff_amf_write_number(&p, 0);
647 ff_amf_write_number(&p, 8192);
648 pkt.size = p - pkt.data;
650 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
652
653 return ret;
654}
655
656/**
657 * Generate 'releaseStream' call and send it to the server. It should make
658 * the server release some channel for media streams.
659 */
661{
663 uint8_t *p;
664 int ret;
665
667 0, 29 + strlen(rt->playpath))) < 0)
668 return ret;
669
670 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
671 p = pkt.data;
672 ff_amf_write_string(&p, "releaseStream");
676
677 return rtmp_send_packet(rt, &pkt, 1);
678}
679
680/**
681 * Generate 'FCPublish' call and send it to the server. It should make
682 * the server prepare for receiving media streams.
683 */
685{
687 uint8_t *p;
688 int ret;
689
691 0, 25 + strlen(rt->playpath))) < 0)
692 return ret;
693
694 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
695 p = pkt.data;
696 ff_amf_write_string(&p, "FCPublish");
700
701 return rtmp_send_packet(rt, &pkt, 1);
702}
703
704/**
705 * Generate 'FCUnpublish' call and send it to the server. It should make
706 * the server destroy stream.
707 */
709{
711 uint8_t *p;
712 int ret;
713
715 0, 27 + strlen(rt->playpath))) < 0)
716 return ret;
717
718 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
719 p = pkt.data;
720 ff_amf_write_string(&p, "FCUnpublish");
724
725 return rtmp_send_packet(rt, &pkt, 0);
726}
727
728/**
729 * Generate 'createStream' call and send it to the server. It should make
730 * the server allocate some channel for media streams.
731 */
733{
735 uint8_t *p;
736 int ret;
737
738 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
739
741 0, 25)) < 0)
742 return ret;
743
744 p = pkt.data;
745 ff_amf_write_string(&p, "createStream");
748
749 return rtmp_send_packet(rt, &pkt, 1);
750}
751
752
753/**
754 * Generate 'deleteStream' call and send it to the server. It should make
755 * the server remove some channel for media streams.
756 */
758{
760 uint8_t *p;
761 int ret;
762
763 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
764
766 0, 34)) < 0)
767 return ret;
768
769 p = pkt.data;
770 ff_amf_write_string(&p, "deleteStream");
774
775 return rtmp_send_packet(rt, &pkt, 0);
776}
777
778/**
779 * Generate 'getStreamLength' call and send it to the server. If the server
780 * knows the duration of the selected stream, it will reply with the duration
781 * in seconds.
782 */
784{
786 uint8_t *p;
787 int ret;
788
790 0, 31 + strlen(rt->playpath))) < 0)
791 return ret;
792
793 p = pkt.data;
794 ff_amf_write_string(&p, "getStreamLength");
798
799 return rtmp_send_packet(rt, &pkt, 1);
800}
801
802/**
803 * Generate client buffer time and send it to the server.
804 */
806{
808 uint8_t *p;
809 int ret;
810
812 1, 10)) < 0)
813 return ret;
814
815 p = pkt.data;
816 bytestream_put_be16(&p, 3); // SetBuffer Length
817 bytestream_put_be32(&p, rt->stream_id);
818 bytestream_put_be32(&p, rt->client_buffer_time);
819
820 return rtmp_send_packet(rt, &pkt, 0);
821}
822
823/**
824 * Generate 'play' call and send it to the server, then ping the server
825 * to start actual playing.
826 */
828{
830 uint8_t *p;
831 int ret;
832
833 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
834
836 0, 29 + strlen(rt->playpath))) < 0)
837 return ret;
838
839 pkt.extra = rt->stream_id;
840
841 p = pkt.data;
842 ff_amf_write_string(&p, "play");
846 ff_amf_write_number(&p, rt->live * 1000);
847
848 return rtmp_send_packet(rt, &pkt, 1);
849}
850
851static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
852{
854 uint8_t *p;
855 int ret;
856
857 av_log(s, AV_LOG_DEBUG, "Sending seek command for timestamp %"PRId64"\n",
858 timestamp);
859
860 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 26)) < 0)
861 return ret;
862
863 pkt.extra = rt->stream_id;
864
865 p = pkt.data;
866 ff_amf_write_string(&p, "seek");
867 ff_amf_write_number(&p, 0); //no tracking back responses
868 ff_amf_write_null(&p); //as usual, the first null param
869 ff_amf_write_number(&p, timestamp); //where we want to jump
870
871 return rtmp_send_packet(rt, &pkt, 1);
872}
873
874/**
875 * Generate a pause packet that either pauses or unpauses the current stream.
876 */
877static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
878{
880 uint8_t *p;
881 int ret;
882
883 av_log(s, AV_LOG_DEBUG, "Sending pause command for timestamp %d\n",
884 timestamp);
885
886 if ((ret = ff_rtmp_packet_create(&pkt, 3, RTMP_PT_INVOKE, 0, 29)) < 0)
887 return ret;
888
889 pkt.extra = rt->stream_id;
890
891 p = pkt.data;
892 ff_amf_write_string(&p, "pause");
893 ff_amf_write_number(&p, 0); //no tracking back responses
894 ff_amf_write_null(&p); //as usual, the first null param
895 ff_amf_write_bool(&p, pause); // pause or unpause
896 ff_amf_write_number(&p, timestamp); //where we pause the stream
897
898 return rtmp_send_packet(rt, &pkt, 1);
899}
900
901/**
902 * Generate 'publish' call and send it to the server.
903 */
905{
907 uint8_t *p;
908 int ret;
909
910 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
911
913 0, 30 + strlen(rt->playpath))) < 0)
914 return ret;
915
916 pkt.extra = rt->stream_id;
917
918 p = pkt.data;
919 ff_amf_write_string(&p, "publish");
923 ff_amf_write_string(&p, "live");
924
925 return rtmp_send_packet(rt, &pkt, 1);
926}
927
928/**
929 * Generate ping reply and send it to the server.
930 */
932{
934 uint8_t *p;
935 int ret;
936
937 if (ppkt->size < 6) {
938 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
939 ppkt->size);
940 return AVERROR_INVALIDDATA;
941 }
942
944 ppkt->timestamp + 1, 6)) < 0)
945 return ret;
946
947 p = pkt.data;
948 bytestream_put_be16(&p, 7); // PingResponse
949 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
950
951 return rtmp_send_packet(rt, &pkt, 0);
952}
953
954/**
955 * Generate SWF verification message and send it to the server.
956 */
958{
960 uint8_t *p;
961 int ret;
962
963 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
965 0, 44)) < 0)
966 return ret;
967
968 p = pkt.data;
969 bytestream_put_be16(&p, 27);
970 memcpy(p, rt->swfverification, 42);
971
972 return rtmp_send_packet(rt, &pkt, 0);
973}
974
975/**
976 * Generate window acknowledgement size message and send it to the server.
977 */
979{
981 uint8_t *p;
982 int ret;
983
985 0, 4)) < 0)
986 return ret;
987
988 p = pkt.data;
989 bytestream_put_be32(&p, rt->max_sent_unacked);
990
991 return rtmp_send_packet(rt, &pkt, 0);
992}
993
994/**
995 * Generate check bandwidth message and send it to the server.
996 */
998{
1000 uint8_t *p;
1001 int ret;
1002
1004 0, 21)) < 0)
1005 return ret;
1006
1007 p = pkt.data;
1008 ff_amf_write_string(&p, "_checkbw");
1011
1012 return rtmp_send_packet(rt, &pkt, 1);
1013}
1014
1015/**
1016 * Generate report on bytes read so far and send it to the server.
1017 */
1018static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
1019{
1021 uint8_t *p;
1022 int ret;
1023
1025 ts, 4)) < 0)
1026 return ret;
1027
1028 p = pkt.data;
1029 bytestream_put_be32(&p, rt->bytes_read);
1030
1031 return rtmp_send_packet(rt, &pkt, 0);
1032}
1033
1035 const char *subscribe)
1036{
1038 uint8_t *p;
1039 int ret;
1040
1042 0, 27 + strlen(subscribe))) < 0)
1043 return ret;
1044
1045 p = pkt.data;
1046 ff_amf_write_string(&p, "FCSubscribe");
1049 ff_amf_write_string(&p, subscribe);
1050
1051 return rtmp_send_packet(rt, &pkt, 1);
1052}
1053
1054/**
1055 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
1056 * will be stored) into that packet.
1057 *
1058 * @param buf handshake data (1536 bytes)
1059 * @param encrypted use an encrypted connection (RTMPE)
1060 * @return offset to the digest inside input data
1061 */
1063{
1064 int ret, digest_pos;
1065
1066 if (encrypted)
1067 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
1068 else
1069 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
1070
1071 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1073 buf + digest_pos);
1074 if (ret < 0)
1075 return ret;
1076
1077 return digest_pos;
1078}
1079
1080/**
1081 * Verify that the received server response has the expected digest value.
1082 *
1083 * @param buf handshake data received from the server (1536 bytes)
1084 * @param off position to search digest offset from
1085 * @return 0 if digest is valid, digest position otherwise
1086 */
1087static int rtmp_validate_digest(uint8_t *buf, int off)
1088{
1089 uint8_t digest[32];
1090 int ret, digest_pos;
1091
1092 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
1093
1094 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
1096 digest);
1097 if (ret < 0)
1098 return ret;
1099
1100 if (!memcmp(digest, buf + digest_pos, 32))
1101 return digest_pos;
1102 return 0;
1103}
1104
1106 uint8_t *buf)
1107{
1108 uint8_t *p;
1109 int ret;
1110
1111 if (rt->swfhash_len != 32) {
1113 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1114 return AVERROR(EINVAL);
1115 }
1116
1117 p = &rt->swfverification[0];
1118 bytestream_put_byte(&p, 1);
1119 bytestream_put_byte(&p, 1);
1120 bytestream_put_be32(&p, rt->swfsize);
1121 bytestream_put_be32(&p, rt->swfsize);
1122
1123 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
1124 return ret;
1125
1126 return 0;
1127}
1128
1129#if CONFIG_ZLIB
1130static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
1131 uint8_t **out_data, int64_t *out_size)
1132{
1133 z_stream zs = { 0 };
1134 void *ptr;
1135 int size;
1136 int ret = 0;
1137
1138 zs.avail_in = in_size;
1139 zs.next_in = in_data;
1140 ret = inflateInit(&zs);
1141 if (ret != Z_OK)
1142 return AVERROR_UNKNOWN;
1143
1144 do {
1145 uint8_t tmp_buf[16384];
1146
1147 zs.avail_out = sizeof(tmp_buf);
1148 zs.next_out = tmp_buf;
1149
1150 ret = inflate(&zs, Z_NO_FLUSH);
1151 if (ret != Z_OK && ret != Z_STREAM_END) {
1152 ret = AVERROR_UNKNOWN;
1153 goto fail;
1154 }
1155
1156 size = sizeof(tmp_buf) - zs.avail_out;
1157 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1158 ret = AVERROR(ENOMEM);
1159 goto fail;
1160 }
1161 *out_data = ptr;
1162
1163 memcpy(*out_data + *out_size, tmp_buf, size);
1164 *out_size += size;
1165 } while (zs.avail_out == 0);
1166
1167fail:
1168 inflateEnd(&zs);
1169 return ret;
1170}
1171#endif
1172
1174{
1175 RTMPContext *rt = s->priv_data;
1176 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1177 int64_t in_size;
1178 URLContext *stream = NULL;
1179 char swfhash[32];
1180 int swfsize;
1181 int ret = 0;
1182
1183 /* Get the SWF player file. */
1184 if ((ret = ffurl_open_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1185 &s->interrupt_callback, NULL,
1186 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
1187 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1188 goto fail;
1189 }
1190
1191 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1192 ret = AVERROR(EIO);
1193 goto fail;
1194 }
1195
1196 if (!(in_data = av_malloc(in_size))) {
1197 ret = AVERROR(ENOMEM);
1198 goto fail;
1199 }
1200
1201 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1202 goto fail;
1203
1204 if (in_size < 3) {
1205 ret = AVERROR_INVALIDDATA;
1206 goto fail;
1207 }
1208
1209 if (!memcmp(in_data, "CWS", 3)) {
1210#if CONFIG_ZLIB
1212 if (in_size < 8) {
1213 ret = AVERROR_INVALIDDATA;
1214 goto fail;
1215 }
1216 /* Decompress the SWF player file using Zlib. */
1217 if (!(out_data = av_malloc(8))) {
1218 ret = AVERROR(ENOMEM);
1219 goto fail;
1220 }
1221 *in_data = 'F'; // magic stuff
1222 memcpy(out_data, in_data, 8);
1223 out_size = 8;
1224
1225 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1226 &out_data, &out_size)) < 0)
1227 goto fail;
1228 swfsize = out_size;
1229 swfdata = out_data;
1230#else
1232 "Zlib is required for decompressing the SWF player file.\n");
1233 ret = AVERROR(EINVAL);
1234 goto fail;
1235#endif
1236 } else {
1237 swfsize = in_size;
1238 swfdata = in_data;
1239 }
1240
1241 /* Compute the SHA256 hash of the SWF player file. */
1242 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1243 "Genuine Adobe Flash Player 001", 30,
1244 swfhash)) < 0)
1245 goto fail;
1246
1247 /* Set SWFVerification parameters. */
1248 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1249 rt->swfsize = swfsize;
1250
1251fail:
1252 av_freep(&in_data);
1253 av_freep(&out_data);
1254 ffurl_close(stream);
1255 return ret;
1256}
1257
1258/**
1259 * Perform handshake with the server by means of exchanging pseudorandom data
1260 * signed with HMAC-SHA2 digest.
1261 *
1262 * @return 0 if handshake succeeds, negative value otherwise
1263 */
1265{
1266 AVLFG rnd;
1267 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1268 3, // unencrypted data
1269 0, 0, 0, 0, // client uptime
1274 };
1275 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1276 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1277 int i;
1278 int server_pos, client_pos;
1279 uint8_t digest[32], signature[32];
1280 int ret;
1281#if CONFIG_FFRTMPCRYPT_PROTOCOL
1282 int type = 0;
1283#endif
1284
1285 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1286
1287 av_lfg_init(&rnd, 0xDEADC0DE);
1288 // generate handshake packet - 1536 bytes of pseudorandom data
1289 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1290 tosend[i] = av_lfg_get(&rnd) >> 24;
1291
1292#if CONFIG_FFRTMPCRYPT_PROTOCOL
1293 if (rt->encrypted) {
1294 /* When the client wants to use RTMPE, we have to change the command
1295 * byte to 0x06 which means to use encrypted data and we have to set
1296 * the flash version to at least 9.0.115.0. */
1297 tosend[0] = 6;
1298 tosend[5] = 128;
1299 tosend[6] = 0;
1300 tosend[7] = 3;
1301 tosend[8] = 2;
1302
1303 /* Initialize the Diffie-Hellmann context and generate the public key
1304 * to send to the server. */
1305 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1306 return ret;
1307 }
1308#endif
1309
1310 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1311 if (client_pos < 0)
1312 return client_pos;
1313
1314 if ((ret = ffurl_write(rt->stream, tosend,
1315 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1316 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1317 return ret;
1318 }
1319
1320 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1321 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1322 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1323 return ret;
1324 }
1325
1326 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1328 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1329 return ret;
1330 }
1331
1332 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1333 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1334 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1335
1336 if (rt->is_input && serverdata[5] >= 3) {
1337 server_pos = rtmp_validate_digest(serverdata + 1, 772);
1338 if (server_pos < 0)
1339 return server_pos;
1340
1341 if (!server_pos) {
1342#if CONFIG_FFRTMPCRYPT_PROTOCOL
1343 type = 1;
1344#endif
1345 server_pos = rtmp_validate_digest(serverdata + 1, 8);
1346 if (server_pos < 0)
1347 return server_pos;
1348
1349 if (!server_pos) {
1350 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1351 return AVERROR(EIO);
1352 }
1353 }
1354
1355 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1356 * key are the last 32 bytes of the server handshake. */
1357 if (rt->swfsize) {
1358 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1359 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1360 return ret;
1361 }
1362
1363 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1365 digest);
1366 if (ret < 0)
1367 return ret;
1368
1369 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1370 0, digest, 32, signature);
1371 if (ret < 0)
1372 return ret;
1373
1374#if CONFIG_FFRTMPCRYPT_PROTOCOL
1375 if (rt->encrypted) {
1376 /* Compute the shared secret key sent by the server and initialize
1377 * the RC4 encryption. */
1378 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1379 tosend + 1, type)) < 0)
1380 return ret;
1381
1382 /* Encrypt the signature received by the server. */
1383 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1384 }
1385#endif
1386
1387 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1388 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1389 return AVERROR(EIO);
1390 }
1391
1392 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1393 tosend[i] = av_lfg_get(&rnd) >> 24;
1394 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1396 digest);
1397 if (ret < 0)
1398 return ret;
1399
1400 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1401 digest, 32,
1402 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1403 if (ret < 0)
1404 return ret;
1405
1406#if CONFIG_FFRTMPCRYPT_PROTOCOL
1407 if (rt->encrypted) {
1408 /* Encrypt the signature to be send to the server. */
1409 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1410 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1411 serverdata[0]);
1412 }
1413#endif
1414
1415 // write reply back to the server
1416 if ((ret = ffurl_write(rt->stream, tosend,
1418 return ret;
1419
1420#if CONFIG_FFRTMPCRYPT_PROTOCOL
1421 if (rt->encrypted) {
1422 /* Set RC4 keys for encryption and update the keystreams. */
1423 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1424 return ret;
1425 }
1426#endif
1427 } else {
1428#if CONFIG_FFRTMPCRYPT_PROTOCOL
1429 if (rt->encrypted) {
1430 /* Compute the shared secret key sent by the server and initialize
1431 * the RC4 encryption. */
1432 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1433 tosend + 1, 1)) < 0)
1434 return ret;
1435
1436 if (serverdata[0] == 9) {
1437 /* Encrypt the signature received by the server. */
1439 serverdata[0]);
1440 }
1441 }
1442#endif
1443
1444 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1446 return ret;
1447
1448#if CONFIG_FFRTMPCRYPT_PROTOCOL
1449 if (rt->encrypted) {
1450 /* Set RC4 keys for encryption and update the keystreams. */
1451 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1452 return ret;
1453 }
1454#endif
1455 }
1456
1457 return 0;
1458}
1459
1460static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1461 uint32_t *second_int, char *arraydata,
1462 int size)
1463{
1464 int inoutsize;
1465
1466 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1468 if (inoutsize <= 0)
1469 return AVERROR(EIO);
1470 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1471 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1472 " not following standard\n", (int)inoutsize);
1473 return AVERROR(EINVAL);
1474 }
1475
1476 *first_int = AV_RB32(arraydata);
1477 *second_int = AV_RB32(arraydata + 4);
1478 return 0;
1479}
1480
1481static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1482 uint32_t second_int, char *arraydata, int size)
1483{
1484 int inoutsize;
1485
1486 AV_WB32(arraydata, first_int);
1487 AV_WB32(arraydata + 4, second_int);
1488 inoutsize = ffurl_write(rt->stream, arraydata,
1490 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1491 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1492 return AVERROR(EIO);
1493 }
1494
1495 return 0;
1496}
1497
1498/**
1499 * rtmp handshake server side
1500 */
1502{
1504 uint32_t hs_epoch;
1505 uint32_t hs_my_epoch;
1506 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1507 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1508 uint32_t zeroes;
1509 uint32_t temp = 0;
1510 int randomidx = 0;
1511 int inoutsize = 0;
1512 int ret;
1513
1514 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1515 if (inoutsize <= 0) {
1516 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1517 return AVERROR(EIO);
1518 }
1519 // Check Version
1520 if (buffer[0] != 3) {
1521 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1522 return AVERROR(EIO);
1523 }
1524 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1526 "Unable to write answer - RTMP S0\n");
1527 return AVERROR(EIO);
1528 }
1529 /* Receive C1 */
1530 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1532 if (ret) {
1533 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1534 return ret;
1535 }
1536 /* Send S1 */
1537 /* By now same epoch will be sent */
1538 hs_my_epoch = hs_epoch;
1539 /* Generate random */
1540 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1541 randomidx += 4)
1542 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1543
1544 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1546 if (ret) {
1547 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1548 return ret;
1549 }
1550 /* Send S2 */
1551 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1553 if (ret) {
1554 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1555 return ret;
1556 }
1557 /* Receive C2 */
1558 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1560 if (ret) {
1561 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1562 return ret;
1563 }
1564 if (temp != hs_my_epoch)
1566 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1567 if (memcmp(buffer + 8, hs_s1 + 8,
1570 "Erroneous C2 Message random does not match up\n");
1571
1572 return 0;
1573}
1574
1576{
1577 RTMPContext *rt = s->priv_data;
1578 int ret;
1579
1580 if (pkt->size < 4) {
1582 "Too short chunk size change packet (%d)\n",
1583 pkt->size);
1584 return AVERROR_INVALIDDATA;
1585 }
1586
1587 if (!rt->is_input) {
1588 /* Send the same chunk size change packet back to the server,
1589 * setting the outgoing chunk size to the same as the incoming one. */
1590 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1591 &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1592 return ret;
1593 rt->out_chunk_size = AV_RB32(pkt->data);
1594 }
1595
1596 rt->in_chunk_size = AV_RB32(pkt->data);
1597 if (rt->in_chunk_size <= 0) {
1598 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1599 rt->in_chunk_size);
1600 return AVERROR_INVALIDDATA;
1601 }
1602 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1603 rt->in_chunk_size);
1604
1605 return 0;
1606}
1607
1609{
1610 RTMPContext *rt = s->priv_data;
1611 int t, ret;
1612
1613 if (pkt->size < 2) {
1614 av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
1615 pkt->size);
1616 return AVERROR_INVALIDDATA;
1617 }
1618
1619 t = AV_RB16(pkt->data);
1620 if (t == 6) { // PingRequest
1621 if ((ret = gen_pong(s, rt, pkt)) < 0)
1622 return ret;
1623 } else if (t == 26) {
1624 if (rt->swfsize) {
1625 if ((ret = gen_swf_verification(s, rt)) < 0)
1626 return ret;
1627 } else {
1628 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1629 }
1630 }
1631
1632 return 0;
1633}
1634
1636{
1637 RTMPContext *rt = s->priv_data;
1638
1639 if (pkt->size < 4) {
1641 "Peer bandwidth packet is less than 4 bytes long (%d)\n",
1642 pkt->size);
1643 return AVERROR_INVALIDDATA;
1644 }
1645
1646 // We currently don't check how much the peer has acknowledged of
1647 // what we have sent. To do that properly, we should call
1648 // gen_window_ack_size here, to tell the peer that we want an
1649 // acknowledgement with (at least) that interval.
1650 rt->max_sent_unacked = AV_RB32(pkt->data);
1651 if (rt->max_sent_unacked <= 0) {
1652 av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
1653 rt->max_sent_unacked);
1654 return AVERROR_INVALIDDATA;
1655
1656 }
1657 av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
1658
1659 return 0;
1660}
1661
1663{
1664 RTMPContext *rt = s->priv_data;
1665
1666 if (pkt->size < 4) {
1668 "Too short window acknowledgement size packet (%d)\n",
1669 pkt->size);
1670 return AVERROR_INVALIDDATA;
1671 }
1672
1673 rt->receive_report_size = AV_RB32(pkt->data);
1674 if (rt->receive_report_size <= 0) {
1675 av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
1677 return AVERROR_INVALIDDATA;
1678 }
1679 av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
1680 // Send an Acknowledgement packet after receiving half the maximum
1681 // size, to make sure the peer can keep on sending without waiting
1682 // for acknowledgements.
1683 rt->receive_report_size >>= 1;
1684
1685 return 0;
1686}
1687
1688static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1689 const char *opaque, const char *challenge)
1690{
1691 uint8_t hash[16];
1692 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1693 struct AVMD5 *md5 = av_md5_alloc();
1694 if (!md5)
1695 return AVERROR(ENOMEM);
1696
1697 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1698
1700 av_md5_update(md5, user, strlen(user));
1701 av_md5_update(md5, salt, strlen(salt));
1702 av_md5_update(md5, rt->password, strlen(rt->password));
1704 av_base64_encode(hashstr, sizeof(hashstr), hash,
1705 sizeof(hash));
1707 av_md5_update(md5, hashstr, strlen(hashstr));
1708 if (opaque)
1709 av_md5_update(md5, opaque, strlen(opaque));
1710 else if (challenge)
1711 av_md5_update(md5, challenge, strlen(challenge));
1712 av_md5_update(md5, challenge2, strlen(challenge2));
1714 av_base64_encode(hashstr, sizeof(hashstr), hash,
1715 sizeof(hash));
1716 snprintf(rt->auth_params, sizeof(rt->auth_params),
1717 "?authmod=%s&user=%s&challenge=%s&response=%s",
1718 "adobe", user, challenge2, hashstr);
1719 if (opaque)
1720 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1721 "&opaque=%s", opaque);
1722
1723 av_free(md5);
1724 return 0;
1725}
1726
1727static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1728{
1729 uint8_t hash[16];
1730 char hashstr1[33], hashstr2[33];
1731 const char *realm = "live";
1732 const char *method = "publish";
1733 const char *qop = "auth";
1734 const char *nc = "00000001";
1735 char cnonce[10];
1736 struct AVMD5 *md5 = av_md5_alloc();
1737 if (!md5)
1738 return AVERROR(ENOMEM);
1739
1740 snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1741
1743 av_md5_update(md5, user, strlen(user));
1744 av_md5_update(md5, ":", 1);
1745 av_md5_update(md5, realm, strlen(realm));
1746 av_md5_update(md5, ":", 1);
1747 av_md5_update(md5, rt->password, strlen(rt->password));
1749 ff_data_to_hex(hashstr1, hash, 16, 1);
1750
1752 av_md5_update(md5, method, strlen(method));
1753 av_md5_update(md5, ":/", 2);
1754 av_md5_update(md5, rt->app, strlen(rt->app));
1755 if (!strchr(rt->app, '/'))
1756 av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1758 ff_data_to_hex(hashstr2, hash, 16, 1);
1759
1761 av_md5_update(md5, hashstr1, strlen(hashstr1));
1762 av_md5_update(md5, ":", 1);
1763 if (nonce)
1764 av_md5_update(md5, nonce, strlen(nonce));
1765 av_md5_update(md5, ":", 1);
1766 av_md5_update(md5, nc, strlen(nc));
1767 av_md5_update(md5, ":", 1);
1768 av_md5_update(md5, cnonce, strlen(cnonce));
1769 av_md5_update(md5, ":", 1);
1770 av_md5_update(md5, qop, strlen(qop));
1771 av_md5_update(md5, ":", 1);
1772 av_md5_update(md5, hashstr2, strlen(hashstr2));
1774 ff_data_to_hex(hashstr1, hash, 16, 1);
1775
1776 snprintf(rt->auth_params, sizeof(rt->auth_params),
1777 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1778 "llnw", user, nonce, cnonce, nc, hashstr1);
1779
1780 av_free(md5);
1781 return 0;
1782}
1783
1784static int handle_connect_error(URLContext *s, const char *desc)
1785{
1786 RTMPContext *rt = s->priv_data;
1787 char buf[300], *ptr, authmod[15];
1788 int i = 0, ret = 0;
1789 const char *user = "", *salt = "", *opaque = NULL,
1790 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1791
1792 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1793 !(cptr = strstr(desc, "authmod=llnw"))) {
1795 "Unknown connect error (unsupported authentication method?)\n");
1796 return AVERROR_UNKNOWN;
1797 }
1798 cptr += strlen("authmod=");
1799 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1800 authmod[i++] = *cptr++;
1801 authmod[i] = '\0';
1802
1803 if (!rt->username[0] || !rt->password[0]) {
1804 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1805 return AVERROR_UNKNOWN;
1806 }
1807
1808 if (strstr(desc, "?reason=authfailed")) {
1809 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1810 return AVERROR_UNKNOWN;
1811 } else if (strstr(desc, "?reason=nosuchuser")) {
1812 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1813 return AVERROR_UNKNOWN;
1814 }
1815
1816 if (rt->auth_tried) {
1817 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1818 return AVERROR_UNKNOWN;
1819 }
1820
1821 rt->auth_params[0] = '\0';
1822
1823 if (strstr(desc, "code=403 need auth")) {
1824 snprintf(rt->auth_params, sizeof(rt->auth_params),
1825 "?authmod=%s&user=%s", authmod, rt->username);
1826 return 0;
1827 }
1828
1829 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1830 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1831 return AVERROR_UNKNOWN;
1832 }
1833
1834 av_strlcpy(buf, cptr + 1, sizeof(buf));
1835 ptr = buf;
1836
1837 while (ptr) {
1838 char *next = strchr(ptr, '&');
1839 char *value = strchr(ptr, '=');
1840 if (next)
1841 *next++ = '\0';
1842 if (value) {
1843 *value++ = '\0';
1844 if (!strcmp(ptr, "user")) {
1845 user = value;
1846 } else if (!strcmp(ptr, "salt")) {
1847 salt = value;
1848 } else if (!strcmp(ptr, "opaque")) {
1849 opaque = value;
1850 } else if (!strcmp(ptr, "challenge")) {
1851 challenge = value;
1852 } else if (!strcmp(ptr, "nonce")) {
1853 nonce = value;
1854 } else {
1855 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1856 }
1857 } else {
1858 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1859 }
1860 ptr = next;
1861 }
1862
1863 if (!strcmp(authmod, "adobe")) {
1864 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1865 return ret;
1866 } else {
1867 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1868 return ret;
1869 }
1870
1871 rt->auth_tried = 1;
1872 return 0;
1873}
1874
1876{
1877 RTMPContext *rt = s->priv_data;
1878 const uint8_t *data_end = pkt->data + pkt->size;
1879 char *tracked_method = NULL;
1880 int level = AV_LOG_ERROR;
1881 uint8_t tmpstr[256];
1882 int ret;
1883
1884 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1885 return ret;
1886
1887 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1888 "description", tmpstr, sizeof(tmpstr))) {
1889 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1890 !strcmp(tracked_method, "releaseStream") ||
1891 !strcmp(tracked_method, "FCSubscribe") ||
1892 !strcmp(tracked_method, "FCPublish"))) {
1893 /* Gracefully ignore Adobe-specific historical artifact errors. */
1895 ret = 0;
1896 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1898 ret = 0;
1899 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1900 ret = handle_connect_error(s, tmpstr);
1901 if (!ret) {
1902 rt->do_reconnect = 1;
1904 }
1905 } else
1906 ret = AVERROR_UNKNOWN;
1907 av_log(s, level, "Server error: %s\n", tmpstr);
1908 }
1909
1910 av_free(tracked_method);
1911 return ret;
1912}
1913
1915{
1916 RTMPContext *rt = s->priv_data;
1917 PutByteContext pbc;
1918 RTMPPacket spkt = { 0 };
1919 int ret;
1920
1921 // Send Stream Begin 1
1923 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1924 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1925 return ret;
1926 }
1927
1928 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1929 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1930 bytestream2_put_be32(&pbc, rt->nb_streamid);
1931
1932 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1933 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1934
1936
1937 return ret;
1938}
1939
1941 const char *status, const char *description, const char *details)
1942{
1943 RTMPContext *rt = s->priv_data;
1944 RTMPPacket spkt = { 0 };
1945 uint8_t *pp;
1946 int ret;
1947
1949 RTMP_PT_INVOKE, 0,
1951 + strlen(status) + strlen(description)
1952 + zstrlen(details))) < 0) {
1953 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1954 return ret;
1955 }
1956
1957 pp = spkt.data;
1958 spkt.extra = pkt->extra;
1959 ff_amf_write_string(&pp, "onStatus");
1960 ff_amf_write_number(&pp, 0);
1961 ff_amf_write_null(&pp);
1962
1964 ff_amf_write_field_name(&pp, "level");
1965 ff_amf_write_string(&pp, "status");
1966 ff_amf_write_field_name(&pp, "code");
1967 ff_amf_write_string(&pp, status);
1968 ff_amf_write_field_name(&pp, "description");
1969 ff_amf_write_string(&pp, description);
1970 if (details) {
1971 ff_amf_write_field_name(&pp, "details");
1972 ff_amf_write_string(&pp, details);
1973 }
1975
1976 spkt.size = pp - spkt.data;
1977 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1978 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1980
1981 return ret;
1982}
1983
1985{
1986 RTMPContext *rt = s->priv_data;
1987 double seqnum;
1988 char filename[128];
1989 char command[64];
1990 int stringlen;
1991 char *pchar;
1992 const uint8_t *p = pkt->data;
1993 uint8_t *pp = NULL;
1994 RTMPPacket spkt = { 0 };
1995 GetByteContext gbc;
1996 int ret;
1997
1998 bytestream2_init(&gbc, p, pkt->size);
1999 if (ff_amf_read_string(&gbc, command, sizeof(command),
2000 &stringlen)) {
2001 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
2002 return AVERROR_INVALIDDATA;
2003 }
2004
2005 ret = ff_amf_read_number(&gbc, &seqnum);
2006 if (ret)
2007 return ret;
2008 ret = ff_amf_read_null(&gbc);
2009 if (ret)
2010 return ret;
2011 if (!strcmp(command, "FCPublish") ||
2012 !strcmp(command, "publish")) {
2013 ret = ff_amf_read_string(&gbc, filename,
2014 sizeof(filename), &stringlen);
2015 if (ret) {
2016 if (ret == AVERROR(EINVAL))
2017 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
2018 else
2019 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
2020 return ret;
2021 }
2022 // check with url
2023 if (s->filename) {
2024 pchar = strrchr(s->filename, '/');
2025 if (!pchar) {
2027 "Unable to find / in url %s, bad format\n",
2028 s->filename);
2029 pchar = s->filename;
2030 }
2031 pchar++;
2032 if (strcmp(pchar, filename))
2033 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
2034 " %s\n", filename, pchar);
2035 }
2036 rt->state = STATE_RECEIVING;
2037 }
2038
2039 if (!strcmp(command, "FCPublish")) {
2041 RTMP_PT_INVOKE, 0,
2043 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2044 return ret;
2045 }
2046 pp = spkt.data;
2047 ff_amf_write_string(&pp, "onFCPublish");
2048 } else if (!strcmp(command, "publish")) {
2049 char statusmsg[sizeof(filename) + 32];
2050 snprintf(statusmsg, sizeof(statusmsg), "%s is now published", filename);
2051 ret = write_begin(s);
2052 if (ret < 0)
2053 return ret;
2054
2055 // Send onStatus(NetStream.Publish.Start)
2056 return write_status(s, pkt, "NetStream.Publish.Start",
2057 statusmsg, filename);
2058 } else if (!strcmp(command, "play")) {
2059 ret = write_begin(s);
2060 if (ret < 0)
2061 return ret;
2062 rt->state = STATE_SENDING;
2063 return write_status(s, pkt, "NetStream.Play.Start",
2064 "playing stream", NULL);
2065 } else {
2067 RTMP_PT_INVOKE, 0,
2069 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2070 return ret;
2071 }
2072 pp = spkt.data;
2073 ff_amf_write_string(&pp, "_result");
2074 ff_amf_write_number(&pp, seqnum);
2075 ff_amf_write_null(&pp);
2076 if (!strcmp(command, "createStream")) {
2077 rt->nb_streamid++;
2078 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2079 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2081 /* By now we don't control which streams are removed in
2082 * deleteStream. There is no stream creation control
2083 * if a client creates more than 2^32 - 2 streams. */
2084 }
2085 }
2086 spkt.size = pp - spkt.data;
2087 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
2088 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2090 return ret;
2091}
2092
2093/**
2094 * Read the AMF_NUMBER response ("_result") to a function call
2095 * (e.g. createStream()). This response should be made up of the AMF_STRING
2096 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2097 * successful response, we will return set the value to number (otherwise number
2098 * will not be changed).
2099 *
2100 * @return 0 if reading the value succeeds, negative value otherwise
2101 */
2102static int read_number_result(RTMPPacket *pkt, double *number)
2103{
2104 // We only need to fit "_result" in this.
2105 uint8_t strbuffer[8];
2106 int stringlen;
2107 double numbuffer;
2108 GetByteContext gbc;
2109
2110 bytestream2_init(&gbc, pkt->data, pkt->size);
2111
2112 // Value 1/4: "_result" as AMF_STRING
2113 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2114 return AVERROR_INVALIDDATA;
2115 if (strcmp(strbuffer, "_result"))
2116 return AVERROR_INVALIDDATA;
2117 // Value 2/4: The callee reference number
2118 if (ff_amf_read_number(&gbc, &numbuffer))
2119 return AVERROR_INVALIDDATA;
2120 // Value 3/4: Null
2121 if (ff_amf_read_null(&gbc))
2122 return AVERROR_INVALIDDATA;
2123 // Value 4/4: The response as AMF_NUMBER
2124 if (ff_amf_read_number(&gbc, &numbuffer))
2125 return AVERROR_INVALIDDATA;
2126 else
2127 *number = numbuffer;
2128
2129 return 0;
2130}
2131
2133{
2134 RTMPContext *rt = s->priv_data;
2135 char *tracked_method = NULL;
2136 int ret = 0;
2137
2138 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2139 return ret;
2140
2141 if (!tracked_method) {
2142 /* Ignore this reply when the current method is not tracked. */
2143 return ret;
2144 }
2145
2146 if (!strcmp(tracked_method, "connect")) {
2147 if (!rt->is_input) {
2148 if ((ret = gen_release_stream(s, rt)) < 0)
2149 goto fail;
2150
2151 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2152 goto fail;
2153 } else {
2154 if ((ret = gen_window_ack_size(s, rt)) < 0)
2155 goto fail;
2156 }
2157
2158 if ((ret = gen_create_stream(s, rt)) < 0)
2159 goto fail;
2160
2161 if (rt->is_input) {
2162 /* Send the FCSubscribe command when the name of live
2163 * stream is defined by the user or if it's a live stream. */
2164 if (rt->subscribe) {
2165 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2166 goto fail;
2167 } else if (rt->live == -1) {
2168 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2169 goto fail;
2170 }
2171 }
2172 } else if (!strcmp(tracked_method, "createStream")) {
2173 double stream_id;
2174 if (read_number_result(pkt, &stream_id)) {
2175 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2176 } else {
2177 rt->stream_id = stream_id;
2178 }
2179
2180 if (!rt->is_input) {
2181 if ((ret = gen_publish(s, rt)) < 0)
2182 goto fail;
2183 } else {
2184 if (rt->live != -1) {
2185 if ((ret = gen_get_stream_length(s, rt)) < 0)
2186 goto fail;
2187 }
2188 if ((ret = gen_play(s, rt)) < 0)
2189 goto fail;
2190 if ((ret = gen_buffer_time(s, rt)) < 0)
2191 goto fail;
2192 }
2193 } else if (!strcmp(tracked_method, "getStreamLength")) {
2194 if (read_number_result(pkt, &rt->duration)) {
2195 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2196 }
2197 }
2198
2199fail:
2200 av_free(tracked_method);
2201 return ret;
2202}
2203
2205{
2206 RTMPContext *rt = s->priv_data;
2207 const uint8_t *data_end = pkt->data + pkt->size;
2208 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2209 uint8_t tmpstr[256];
2210 int i, t;
2211
2212 for (i = 0; i < 2; i++) {
2213 t = ff_amf_tag_size(ptr, data_end);
2214 if (t < 0)
2215 return 1;
2216 ptr += t;
2217 }
2218
2219 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2220 if (!t && !strcmp(tmpstr, "error")) {
2221 t = ff_amf_get_field_value(ptr, data_end,
2222 "description", tmpstr, sizeof(tmpstr));
2223 if (t || !tmpstr[0])
2224 t = ff_amf_get_field_value(ptr, data_end, "code",
2225 tmpstr, sizeof(tmpstr));
2226 if (!t)
2227 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2228 return -1;
2229 }
2230
2231 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2232 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2233 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2234 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2235 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2236 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2237
2238 return 0;
2239}
2240
2242{
2243 RTMPContext *rt = s->priv_data;
2244 int ret = 0;
2245
2246 //TODO: check for the messages sent for wrong state?
2247 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2248 if ((ret = handle_invoke_error(s, pkt)) < 0)
2249 return ret;
2250 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2251 if ((ret = handle_invoke_result(s, pkt)) < 0)
2252 return ret;
2253 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2254 if ((ret = handle_invoke_status(s, pkt)) < 0)
2255 return ret;
2256 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2257 if ((ret = gen_check_bw(s, rt)) < 0)
2258 return ret;
2259 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2260 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2261 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2262 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2263 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2264 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2265 if ((ret = send_invoke_response(s, pkt)) < 0)
2266 return ret;
2267 }
2268
2269 return ret;
2270}
2271
2272static int update_offset(RTMPContext *rt, int size)
2273{
2274 int old_flv_size;
2275
2276 if (size < 0)
2277 return AVERROR(EINVAL);
2278
2279 // generate packet header and put data into buffer for FLV demuxer
2280 if (rt->flv_off < rt->flv_size) {
2281 // There is old unread data in the buffer, thus append at the end
2282 if (rt->flv_size > INT_MAX - size)
2283 return AVERROR(ERANGE);
2284 old_flv_size = rt->flv_size;
2285 rt->flv_size += size;
2286 } else {
2287 // All data has been read, write the new data at the start of the buffer
2288 old_flv_size = 0;
2289 rt->flv_size = size;
2290 rt->flv_off = 0;
2291 }
2292
2293 return old_flv_size;
2294}
2295
2297{
2298 int old_flv_size, ret;
2299 PutByteContext pbc;
2300 const uint8_t *data = pkt->data + skip;
2301 const int size = pkt->size - skip;
2302 uint32_t ts = pkt->timestamp;
2303
2304 if (pkt->type == RTMP_PT_AUDIO) {
2305 rt->has_audio = 1;
2306 } else if (pkt->type == RTMP_PT_VIDEO) {
2307 rt->has_video = 1;
2308 }
2309
2310 if (size > INT_MAX - 15)
2311 return AVERROR(ERANGE);
2312 old_flv_size = update_offset(rt, size + 15);
2313 if (old_flv_size < 0)
2314 return old_flv_size;
2315
2316 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2317 rt->flv_size = rt->flv_off = 0;
2318 return ret;
2319 }
2321 bytestream2_skip_p(&pbc, old_flv_size);
2322 bytestream2_put_byte(&pbc, pkt->type);
2323 bytestream2_put_be24(&pbc, size);
2324 bytestream2_put_be24(&pbc, ts);
2325 bytestream2_put_byte(&pbc, ts >> 24);
2326 bytestream2_put_be24(&pbc, 0);
2328 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2329
2330 return 0;
2331}
2332
2334{
2335 RTMPContext *rt = s->priv_data;
2336 uint8_t commandbuffer[64];
2337 char statusmsg[128];
2338 int stringlen, ret, skip = 0;
2339 GetByteContext gbc;
2340
2341 bytestream2_init(&gbc, pkt->data, pkt->size);
2342 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2343 &stringlen))
2344 return AVERROR_INVALIDDATA;
2345
2346 if (!strcmp(commandbuffer, "onMetaData")) {
2347 // metadata properties should be stored in a mixed array
2348 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2349 // We have found a metaData Array so flv can determine the streams
2350 // from this.
2351 rt->received_metadata = 1;
2352 // skip 32-bit max array index
2353 bytestream2_skip(&gbc, 4);
2354 while (bytestream2_get_bytes_left(&gbc) > 3) {
2355 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2356 &stringlen))
2357 return AVERROR_INVALIDDATA;
2358 // We do not care about the content of the property (yet).
2359 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2360 if (stringlen < 0)
2361 return AVERROR_INVALIDDATA;
2362 bytestream2_skip(&gbc, stringlen);
2363
2364 // The presence of the following properties indicates that the
2365 // respective streams are present.
2366 if (!strcmp(statusmsg, "videocodecid")) {
2367 rt->has_video = 1;
2368 }
2369 if (!strcmp(statusmsg, "audiocodecid")) {
2370 rt->has_audio = 1;
2371 }
2372 }
2373 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2374 return AVERROR_INVALIDDATA;
2375 }
2376 }
2377
2378 // Skip the @setDataFrame string and validate it is a notification
2379 if (!strcmp(commandbuffer, "@setDataFrame")) {
2380 skip = gbc.buffer - pkt->data;
2381 ret = ff_amf_read_string(&gbc, statusmsg,
2382 sizeof(statusmsg), &stringlen);
2383 if (ret < 0)
2384 return AVERROR_INVALIDDATA;
2385 }
2386
2387 return append_flv_data(rt, pkt, skip);
2388}
2389
2390/**
2391 * Parse received packet and possibly perform some action depending on
2392 * the packet contents.
2393 * @return 0 for no errors, negative values for serious errors which prevent
2394 * further communications, positive values for uncritical errors
2395 */
2397{
2398 int ret;
2399
2400#ifdef DEBUG
2402#endif
2403
2404 switch (pkt->type) {
2405 case RTMP_PT_BYTES_READ:
2406 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2407 break;
2408 case RTMP_PT_CHUNK_SIZE:
2409 if ((ret = handle_chunk_size(s, pkt)) < 0)
2410 return ret;
2411 break;
2413 if ((ret = handle_user_control(s, pkt)) < 0)
2414 return ret;
2415 break;
2417 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2418 return ret;
2419 break;
2421 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2422 return ret;
2423 break;
2424 case RTMP_PT_INVOKE:
2425 if ((ret = handle_invoke(s, pkt)) < 0)
2426 return ret;
2427 break;
2428 case RTMP_PT_VIDEO:
2429 case RTMP_PT_AUDIO:
2430 case RTMP_PT_METADATA:
2431 case RTMP_PT_NOTIFY:
2432 /* Audio, Video and Metadata packets are parsed in get_packet() */
2433 break;
2434 default:
2435 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2436 break;
2437 }
2438 return 0;
2439}
2440
2442{
2443 int ret, old_flv_size, type;
2444 PutByteContext pbc;
2445 GetByteContext gbc;
2446 uint32_t size;
2447 uint32_t ts, cts, pts = 0;
2448
2449 old_flv_size = update_offset(rt, pkt->size);
2450 if (old_flv_size < 0)
2451 return old_flv_size;
2452
2453 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2454 rt->flv_size = rt->flv_off = 0;
2455 return ret;
2456 }
2457
2458 bytestream2_init(&gbc, pkt->data, pkt->size);
2460 bytestream2_skip_p(&pbc, old_flv_size);
2461
2462 /* copy data while rewriting timestamps */
2463 ts = pkt->timestamp;
2464
2465 while (bytestream2_get_bytes_left(&gbc) > RTMP_HEADER) {
2466 type = bytestream2_get_byte(&gbc);
2467 size = bytestream2_get_be24(&gbc);
2468 cts = bytestream2_get_be24(&gbc);
2469 cts |= bytestream2_get_byte(&gbc) << 24;
2470 if (!pts)
2471 pts = cts;
2472 ts += cts - pts;
2473 pts = cts;
2474 if (size + 3 + 4 > bytestream2_get_bytes_left(&gbc))
2475 break;
2476 bytestream2_put_byte(&pbc, type);
2477 bytestream2_put_be24(&pbc, size);
2478 bytestream2_put_be24(&pbc, ts);
2479 bytestream2_put_byte(&pbc, ts >> 24);
2480 bytestream2_copy_buffer(&pbc, &gbc, size + 3);
2481 bytestream2_skip(&gbc, 4);
2482 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2483 }
2484 if (bytestream2_tell_p(&pbc) != rt->flv_size) {
2485 av_log(rt, AV_LOG_WARNING, "Incomplete flv packets in "
2486 "RTMP_PT_METADATA packet\n");
2487 rt->flv_size = bytestream2_tell_p(&pbc);
2488 }
2489
2490 return 0;
2491}
2492
2493/**
2494 * Interact with the server by receiving and sending RTMP packets until
2495 * there is some significant data (media data or expected status notification).
2496 *
2497 * @param s reading context
2498 * @param for_header non-zero value tells function to work until it
2499 * gets notification from the server that playing has been started,
2500 * otherwise function will work until some media data is received (or
2501 * an error happens)
2502 * @return 0 for successful operation, negative value in case of error
2503 */
2504static int get_packet(URLContext *s, int for_header)
2505{
2506 RTMPContext *rt = s->priv_data;
2507 int ret;
2508
2509 if (rt->state == STATE_STOPPED)
2510 return AVERROR_EOF;
2511
2512 for (;;) {
2513 RTMPPacket rpkt = { 0 };
2514 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2515 rt->in_chunk_size, &rt->prev_pkt[0],
2516 &rt->nb_prev_pkt[0])) <= 0) {
2517 if (ret == 0) {
2518 return AVERROR(EAGAIN);
2519 } else {
2520 return AVERROR(EIO);
2521 }
2522 }
2523
2524 // Track timestamp for later use
2525 rt->last_timestamp = rpkt.timestamp;
2526
2527 rt->bytes_read += ret;
2528 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2529 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2530 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) {
2532 return ret;
2533 }
2534 rt->last_bytes_read = rt->bytes_read;
2535 }
2536
2537 ret = rtmp_parse_result(s, rt, &rpkt);
2538
2539 // At this point we must check if we are in the seek state and continue
2540 // with the next packet. handle_invoke will get us out of this state
2541 // when the right message is encountered
2542 if (rt->state == STATE_SEEKING) {
2544 // We continue, let the natural flow of things happen:
2545 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2546 continue;
2547 }
2548
2549 if (ret < 0) {//serious error in current packet
2551 return ret;
2552 }
2553 if (rt->do_reconnect && for_header) {
2555 return 0;
2556 }
2557 if (rt->state == STATE_STOPPED) {
2559 return AVERROR_EOF;
2560 }
2561 if (for_header && (rt->state == STATE_PLAYING ||
2562 rt->state == STATE_PUBLISHING ||
2563 rt->state == STATE_SENDING ||
2564 rt->state == STATE_RECEIVING)) {
2566 return 0;
2567 }
2568 if (!rpkt.size || !rt->is_input) {
2570 continue;
2571 }
2572 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2573 ret = append_flv_data(rt, &rpkt, 0);
2575 return ret;
2576 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2577 ret = handle_notify(s, &rpkt);
2579 return ret;
2580 } else if (rpkt.type == RTMP_PT_METADATA) {
2581 ret = handle_metadata(rt, &rpkt);
2583 return ret;
2584 }
2586 }
2587}
2588
2590{
2591 RTMPContext *rt = h->priv_data;
2592 int ret = 0, i, j;
2593
2594 if (!rt->is_input) {
2595 rt->flv_data = NULL;
2596 if (rt->out_pkt.size)
2598 if (rt->state > STATE_FCPUBLISH)
2599 ret = gen_fcunpublish_stream(h, rt);
2600 }
2601 if (rt->state > STATE_HANDSHAKED)
2602 ret = gen_delete_stream(h, rt);
2603 for (i = 0; i < 2; i++) {
2604 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2606 av_freep(&rt->prev_pkt[i]);
2607 }
2608
2610 av_freep(&rt->flv_data);
2611 ffurl_closep(&rt->stream);
2612 return ret;
2613}
2614
2615/**
2616 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2617 * demuxer about the duration of the stream.
2618 *
2619 * This should only be done if there was no real onMetadata packet sent by the
2620 * server at the start of the stream and if we were able to retrieve a valid
2621 * duration via a getStreamLength call.
2622 *
2623 * @return 0 for successful operation, negative value in case of error
2624 */
2626{
2627 // We need to insert the metadata packet directly after the FLV
2628 // header, i.e. we need to move all other already read data by the
2629 // size of our fake metadata packet.
2630
2631 uint8_t* p;
2632 // Keep old flv_data pointer
2633 uint8_t* old_flv_data = rt->flv_data;
2634 // Allocate a new flv_data pointer with enough space for the additional package
2635 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2636 rt->flv_data = old_flv_data;
2637 return AVERROR(ENOMEM);
2638 }
2639
2640 // Copy FLV header
2641 memcpy(rt->flv_data, old_flv_data, 13);
2642 // Copy remaining packets
2643 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2644 // Increase the size by the injected packet
2645 rt->flv_size += 55;
2646 // Delete the old FLV data
2647 av_freep(&old_flv_data);
2648
2649 p = rt->flv_data + 13;
2650 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2651 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2652 bytestream_put_be24(&p, 0); // timestamp
2653 bytestream_put_be32(&p, 0); // reserved
2654
2655 // first event name as a string
2656 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2657 // "onMetaData" as AMF string
2658 bytestream_put_be16(&p, 10);
2659 bytestream_put_buffer(&p, "onMetaData", 10);
2660
2661 // mixed array (hash) with size and string/type/data tuples
2662 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2663 bytestream_put_be32(&p, 1); // metadata_count
2664
2665 // "duration" as AMF string
2666 bytestream_put_be16(&p, 8);
2667 bytestream_put_buffer(&p, "duration", 8);
2668 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2669 bytestream_put_be64(&p, av_double2int(rt->duration));
2670
2671 // Finalise object
2672 bytestream_put_be16(&p, 0); // Empty string
2673 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2674 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2675
2676 return 0;
2677}
2678
2679/**
2680 * Open RTMP connection and verify that the stream can be played.
2681 *
2682 * URL syntax: rtmp://server[:port][/app][/playpath]
2683 * where 'app' is first one or two directories in the path
2684 * (e.g. /ondemand/, /flash/live/, etc.)
2685 * and 'playpath' is a file name (the rest of the path,
2686 * may be prefixed with "mp4:")
2687 */
2688static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2689{
2690 RTMPContext *rt = s->priv_data;
2691 char proto[8], hostname[256], path[1024], auth[100], *fname;
2692 char *old_app, *qmark, *n, fname_buffer[1024];
2693 uint8_t buf[2048];
2694 int port;
2695 int ret;
2696
2697 if (rt->listen_timeout > 0)
2698 rt->listen = 1;
2699
2700 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2701
2702 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2703 hostname, sizeof(hostname), &port,
2704 path, sizeof(path), s->filename);
2705
2706 n = strchr(path, ' ');
2707 if (n) {
2709 "Detected librtmp style URL parameters, these aren't supported "
2710 "by the libavformat internal RTMP handler currently enabled. "
2711 "See the documentation for the correct way to pass parameters.\n");
2712 *n = '\0'; // Trim not supported part
2713 }
2714
2715 if (auth[0]) {
2716 char *ptr = strchr(auth, ':');
2717 if (ptr) {
2718 *ptr = '\0';
2719 av_strlcpy(rt->username, auth, sizeof(rt->username));
2720 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2721 }
2722 }
2723
2724 if (rt->listen && strcmp(proto, "rtmp")) {
2725 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2726 proto);
2727 return AVERROR(EINVAL);
2728 }
2729 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2730 if (!strcmp(proto, "rtmpts"))
2731 av_dict_set(opts, "ffrtmphttp_tls", "1", AV_DICT_MATCH_CASE);
2732
2733 /* open the http tunneling connection */
2734 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2735 } else if (!strcmp(proto, "rtmps")) {
2736 /* open the tls connection */
2737 if (port < 0)
2738 port = RTMPS_DEFAULT_PORT;
2739 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2740 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2741 if (!strcmp(proto, "rtmpte"))
2742 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2743
2744 /* open the encrypted connection */
2745 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2746 rt->encrypted = 1;
2747 } else {
2748 /* open the tcp connection */
2749 if (port < 0)
2750 port = RTMP_DEFAULT_PORT;
2751 if (rt->listen)
2752 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2753 "?listen&listen_timeout=%d&tcp_nodelay=%d",
2754 rt->listen_timeout < 0 ? -1 : rt->listen_timeout * 1000,
2755 rt->tcp_nodelay);
2756 else
2757 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, "?tcp_nodelay=%d", rt->tcp_nodelay);
2758 }
2759
2760reconnect:
2761 if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2762 &s->interrupt_callback, opts,
2763 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2764 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2765 goto fail;
2766 }
2767
2768 if (rt->swfverify) {
2769 if ((ret = rtmp_calc_swfhash(s)) < 0)
2770 goto fail;
2771 }
2772
2773 rt->state = STATE_START;
2774 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2775 goto fail;
2776 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2777 goto fail;
2778
2779 rt->out_chunk_size = 128;
2780 rt->in_chunk_size = 128; // Probably overwritten later
2781 rt->state = STATE_HANDSHAKED;
2782
2783 // Keep the application name when it has been defined by the user.
2784 old_app = rt->app;
2785
2787 if (!rt->app) {
2788 ret = AVERROR(ENOMEM);
2789 goto fail;
2790 }
2791
2792 //extract "app" part from path
2793 qmark = strchr(path, '?');
2794 if (qmark && strstr(qmark, "slist=")) {
2795 char* amp;
2796 // After slist we have the playpath, the full path is used as app
2797 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2798 fname = strstr(path, "slist=") + 6;
2799 // Strip any further query parameters from fname
2800 amp = strchr(fname, '&');
2801 if (amp) {
2802 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2803 sizeof(fname_buffer)));
2804 fname = fname_buffer;
2805 }
2806 } else if (!strncmp(path, "/ondemand/", 10)) {
2807 fname = path + 10;
2808 memcpy(rt->app, "ondemand", 9);
2809 } else {
2810 char *next = *path ? path + 1 : path;
2811 char *p = strchr(next, '/');
2812 if (!p) {
2813 if (old_app) {
2814 // If name of application has been defined by the user, assume that
2815 // playpath is provided in the URL
2816 fname = next;
2817 } else {
2818 fname = NULL;
2819 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2820 }
2821 } else {
2822 // make sure we do not mismatch a playpath for an application instance
2823 char *c = strchr(p + 1, ':');
2824 fname = strchr(p + 1, '/');
2825 if (!fname || (c && c < fname)) {
2826 fname = p + 1;
2827 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2828 } else {
2829 fname++;
2830 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2831 }
2832 }
2833 }
2834
2835 if (old_app) {
2836 // The name of application has been defined by the user, override it.
2837 if (strlen(old_app) >= APP_MAX_LENGTH) {
2838 ret = AVERROR(EINVAL);
2839 goto fail;
2840 }
2841 av_free(rt->app);
2842 rt->app = old_app;
2843 }
2844
2845 if (!rt->playpath) {
2846 int max_len = 1;
2847 if (fname)
2848 max_len = strlen(fname) + 5; // add prefix "mp4:"
2849 rt->playpath = av_malloc(max_len);
2850 if (!rt->playpath) {
2851 ret = AVERROR(ENOMEM);
2852 goto fail;
2853 }
2854
2855 if (fname) {
2856 int len = strlen(fname);
2857 if (!strchr(fname, ':') && len >= 4 &&
2858 (!strcmp(fname + len - 4, ".f4v") ||
2859 !strcmp(fname + len - 4, ".mp4"))) {
2860 memcpy(rt->playpath, "mp4:", 5);
2861 } else {
2862 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2863 fname[len - 4] = '\0';
2864 rt->playpath[0] = 0;
2865 }
2866 av_strlcat(rt->playpath, fname, max_len);
2867 } else {
2868 rt->playpath[0] = '\0';
2869 }
2870 }
2871
2872 if (!rt->tcurl) {
2874 if (!rt->tcurl) {
2875 ret = AVERROR(ENOMEM);
2876 goto fail;
2877 }
2878 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2879 port, "/%s", rt->app);
2880 }
2881
2882 if (!rt->flashver) {
2884 if (!rt->flashver) {
2885 ret = AVERROR(ENOMEM);
2886 goto fail;
2887 }
2888 if (rt->is_input) {
2889 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2892 } else {
2894 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2895 }
2896 }
2897 if ( strlen(rt->flashver) > FLASHVER_MAX_LENGTH
2898 || strlen(rt->tcurl ) > TCURL_MAX_LENGTH
2899 ) {
2900 ret = AVERROR(EINVAL);
2901 goto fail;
2902 }
2903
2904 rt->receive_report_size = 1048576;
2905 rt->bytes_read = 0;
2906 rt->has_audio = 0;
2907 rt->has_video = 0;
2908 rt->received_metadata = 0;
2909 rt->last_bytes_read = 0;
2910 rt->max_sent_unacked = 2500000;
2911 rt->duration = 0;
2912
2913 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2914 proto, path, rt->app, rt->playpath);
2915 if (!rt->listen) {
2916 if ((ret = gen_connect(s, rt)) < 0)
2917 goto fail;
2918 } else {
2919 if ((ret = read_connect(s, s->priv_data)) < 0)
2920 goto fail;
2921 }
2922
2923 do {
2924 ret = get_packet(s, 1);
2925 } while (ret == AVERROR(EAGAIN));
2926 if (ret < 0)
2927 goto fail;
2928
2929 if (rt->do_reconnect) {
2930 int i;
2931 ffurl_closep(&rt->stream);
2932 rt->do_reconnect = 0;
2933 rt->nb_invokes = 0;
2934 for (i = 0; i < 2; i++)
2935 memset(rt->prev_pkt[i], 0,
2936 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2938 goto reconnect;
2939 }
2940
2941 if (rt->is_input) {
2942 // generate FLV header for demuxer
2943 rt->flv_size = 13;
2944 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2945 goto fail;
2946 rt->flv_off = 0;
2947 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2948
2949 // Read packets until we reach the first A/V packet or read metadata.
2950 // If there was a metadata package in front of the A/V packets, we can
2951 // build the FLV header from this. If we do not receive any metadata,
2952 // the FLV decoder will allocate the needed streams when their first
2953 // audio or video packet arrives.
2954 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2955 if ((ret = get_packet(s, 0)) < 0)
2956 goto fail;
2957 }
2958
2959 // Either after we have read the metadata or (if there is none) the
2960 // first packet of an A/V stream, we have a better knowledge about the
2961 // streams, so set the FLV header accordingly.
2962 if (rt->has_audio) {
2964 }
2965 if (rt->has_video) {
2967 }
2968
2969 // If we received the first packet of an A/V stream and no metadata but
2970 // the server returned a valid duration, create a fake metadata packet
2971 // to inform the FLV decoder about the duration.
2972 if (!rt->received_metadata && rt->duration > 0) {
2973 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2974 goto fail;
2975 }
2976 } else {
2977 rt->flv_size = 0;
2978 rt->flv_data = NULL;
2979 rt->flv_off = 0;
2980 rt->skip_bytes = 13;
2981 }
2982
2983 s->max_packet_size = rt->stream->max_packet_size;
2984 s->is_streamed = 1;
2985 return 0;
2986
2987fail:
2988 rtmp_close(s);
2989 return ret;
2990}
2991
2992static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2993{
2994 RTMPContext *rt = s->priv_data;
2995 int orig_size = size;
2996 int ret;
2997
2998 while (size > 0) {
2999 int data_left = rt->flv_size - rt->flv_off;
3000
3001 if (data_left >= size) {
3002 memcpy(buf, rt->flv_data + rt->flv_off, size);
3003 rt->flv_off += size;
3004 return orig_size;
3005 }
3006 if (data_left > 0) {
3007 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
3008 buf += data_left;
3009 size -= data_left;
3010 rt->flv_off = rt->flv_size;
3011 return data_left;
3012 }
3013 if ((ret = get_packet(s, 0)) < 0)
3014 return ret;
3015 }
3016 return orig_size;
3017}
3018
3019static int64_t rtmp_seek(void *opaque, int stream_index, int64_t timestamp,
3020 int flags)
3021{
3022 URLContext *s = opaque;
3023 RTMPContext *rt = s->priv_data;
3024 int ret;
3026 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
3027 stream_index, timestamp, flags);
3028 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
3030 "Unable to send seek command on stream index %d at timestamp "
3031 "%"PRId64" with flags %08x\n",
3032 stream_index, timestamp, flags);
3033 return ret;
3034 }
3035 rt->flv_off = rt->flv_size;
3036 rt->state = STATE_SEEKING;
3037 return timestamp;
3038}
3039
3040static int rtmp_pause(void *opaque, int pause)
3041{
3042 URLContext *s = opaque;
3043 RTMPContext *rt = s->priv_data;
3044 int ret;
3045 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
3046 rt->last_timestamp);
3047 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
3048 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
3049 rt->last_timestamp);
3050 return ret;
3051 }
3052 return 0;
3053}
3054
3055static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
3056{
3057 RTMPContext *rt = s->priv_data;
3058 int size_temp = size;
3059 int pktsize, pkttype, copy;
3060 uint32_t ts;
3061 const uint8_t *buf_temp = buf;
3062 uint8_t c;
3063 int ret;
3064
3065 do {
3066 if (rt->skip_bytes) {
3067 int skip = FFMIN(rt->skip_bytes, size_temp);
3068 buf_temp += skip;
3069 size_temp -= skip;
3070 rt->skip_bytes -= skip;
3071 continue;
3072 }
3073
3074 if (rt->flv_header_bytes < RTMP_HEADER) {
3075 const uint8_t *header = rt->flv_header;
3077
3078 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
3080 rt->flv_header_bytes += copy;
3081 size_temp -= copy;
3082 if (rt->flv_header_bytes < RTMP_HEADER)
3083 break;
3084
3085 pkttype = bytestream_get_byte(&header);
3086 pktsize = bytestream_get_be24(&header);
3087 ts = bytestream_get_be24(&header);
3088 ts |= bytestream_get_byte(&header) << 24;
3089 bytestream_get_be24(&header);
3090 rt->flv_size = pktsize;
3091
3092 if (pkttype == RTMP_PT_VIDEO)
3094
3095 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
3096 pkttype == RTMP_PT_NOTIFY) {
3097 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
3098 &rt->nb_prev_pkt[1],
3099 channel)) < 0)
3100 return ret;
3101 // Force sending a full 12 bytes header by clearing the
3102 // channel id, to make it not match a potential earlier
3103 // packet in the same channel.
3104 rt->prev_pkt[1][channel].channel_id = 0;
3105 }
3106
3107 //this can be a big packet, it's better to send it right here
3108 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
3109 pkttype, ts, pktsize)) < 0)
3110 return ret;
3111
3112 // If rt->listen, then we're running as a a server and should
3113 // use the ID that we've sent in Stream Begin and in the
3114 // _result to createStream.
3115 // Otherwise, we're running as a client and should use the ID
3116 // that we've received in the createStream from the server.
3117 rt->out_pkt.extra = (rt->listen) ? rt->nb_streamid : rt->stream_id;
3118 rt->flv_data = rt->out_pkt.data;
3119 }
3120
3121 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3122 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3123 rt->flv_off += copy;
3124 size_temp -= copy;
3125
3126 if (rt->flv_off == rt->flv_size) {
3127 rt->skip_bytes = 4;
3128
3129 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3130 // For onMetaData and |RtmpSampleAccess packets, we want
3131 // @setDataFrame prepended to the packet before it gets sent.
3132 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3133 // and onCuePoint).
3134 uint8_t commandbuffer[64];
3135 int stringlen = 0;
3136 GetByteContext gbc;
3137
3138 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3139 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3140 &stringlen)) {
3141 if (!strcmp(commandbuffer, "onMetaData") ||
3142 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3143 uint8_t *ptr;
3144 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3145 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3146 return ret;
3147 }
3148 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3149 rt->out_pkt.size += 16;
3150 ptr = rt->out_pkt.data;
3151 ff_amf_write_string(&ptr, "@setDataFrame");
3152 }
3153 }
3154 }
3155
3156 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3157 return ret;
3158 rt->flv_size = 0;
3159 rt->flv_off = 0;
3160 rt->flv_header_bytes = 0;
3161 rt->flv_nb_packets++;
3162 }
3163 } while (buf_temp - buf < size);
3164
3165 if (rt->flv_nb_packets < rt->flush_interval)
3166 return size;
3167 rt->flv_nb_packets = 0;
3168
3169 /* set stream into nonblocking mode */
3171
3172 /* try to read one byte from the stream */
3173 ret = ffurl_read(rt->stream, &c, 1);
3174
3175 /* switch the stream back into blocking mode */
3177
3178 if (ret == AVERROR(EAGAIN)) {
3179 /* no incoming data to handle */
3180 return size;
3181 } else if (ret < 0) {
3182 return ret;
3183 } else if (ret == 1) {
3184 RTMPPacket rpkt = { 0 };
3185
3186 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3187 rt->in_chunk_size,
3188 &rt->prev_pkt[0],
3189 &rt->nb_prev_pkt[0], c)) <= 0)
3190 return ret;
3191
3192 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3193 return ret;
3194
3196 }
3197
3198 return size;
3199}
3200
3201#define OFFSET(x) offsetof(RTMPContext, x)
3202#define DEC AV_OPT_FLAG_DECODING_PARAM
3203#define ENC AV_OPT_FLAG_ENCODING_PARAM
3204
3205static const AVOption rtmp_options[] = {
3206 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3207 {"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},
3208 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3209 {"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},
3210 {"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},
3211 {"rtmp_enhanced_codecs", "Specify the codec(s) to use in an enhanced rtmp live stream", OFFSET(enhanced_codecs), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, ENC},
3212 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = -2}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_live"},
3213 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, .unit = "rtmp_live"},
3214 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, .unit = "rtmp_live"},
3215 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, .unit = "rtmp_live"},
3216 {"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},
3217 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3218 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3219 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3220 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3221 {"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},
3222 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3223 {"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},
3224 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_listen" },
3225 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_listen" },
3226 {"tcp_nodelay", "Use TCP_NODELAY to disable Nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC|ENC},
3227 {"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, .unit = "rtmp_listen" },
3228 { NULL },
3229};
3230
3231#define RTMP_PROTOCOL_0(flavor)
3232#define RTMP_PROTOCOL_1(flavor) \
3233static const AVClass flavor##_class = { \
3234 .class_name = #flavor, \
3235 .item_name = av_default_item_name, \
3236 .option = rtmp_options, \
3237 .version = LIBAVUTIL_VERSION_INT, \
3238}; \
3239 \
3240const URLProtocol ff_##flavor##_protocol = { \
3241 .name = #flavor, \
3242 .url_open2 = rtmp_open, \
3243 .url_read = rtmp_read, \
3244 .url_read_seek = rtmp_seek, \
3245 .url_read_pause = rtmp_pause, \
3246 .url_write = rtmp_write, \
3247 .url_close = rtmp_close, \
3248 .priv_data_size = sizeof(RTMPContext), \
3249 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3250 .priv_data_class= &flavor##_class, \
3251};
3252#define RTMP_PROTOCOL_2(flavor, enabled) \
3253 RTMP_PROTOCOL_ ## enabled(flavor)
3254#define RTMP_PROTOCOL_3(flavor, config) \
3255 RTMP_PROTOCOL_2(flavor, config)
3256#define RTMP_PROTOCOL(flavor, uppercase) \
3257 RTMP_PROTOCOL_3(flavor, CONFIG_ ## uppercase ## _PROTOCOL)
3258
3259RTMP_PROTOCOL(rtmp, RTMP)
3260RTMP_PROTOCOL(rtmpe, RTMPE)
3261RTMP_PROTOCOL(rtmps, RTMPS)
3262RTMP_PROTOCOL(rtmpt, RTMPT)
3263RTMP_PROTOCOL(rtmpte, RTMPTE)
3264RTMP_PROTOCOL(rtmpts, RTMPTS)
static struct AVMD5 * md5
static int out_size
static uint8_t hash[HASH_SIZE]
static AVDictionary * opts
Main libavformat public API header.
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition avio.c:461
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:656
int ffurl_close(URLContext *h)
Definition avio.c:679
int ffurl_read_complete(URLContext *h, unsigned char *buf, int size)
Read as many bytes as possible (up to size), calling the read function multiple times if necessary.
Definition avio.c:625
#define AVIO_FLAG_READ
read-only
Definition avio.h:617
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition avio.h:468
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:618
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition avio.h:619
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:636
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition avstring.c:103
static void BS_FUNC skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
static av_always_inline int bytestream2_tell_p(const PutByteContext *p)
Definition bytestream.h:197
static av_always_inline unsigned int bytestream_get_buffer(const uint8_t **b, uint8_t *dst, unsigned int size)
Definition bytestream.h:363
static av_always_inline void bytestream_put_buffer(uint8_t **b, const uint8_t *src, unsigned int size)
Definition bytestream.h:372
static av_always_inline void bytestream2_init_writer(PutByteContext *p, uint8_t *buf, int buf_size)
Definition bytestream.h:147
static av_always_inline void bytestream2_skip_p(PutByteContext *p, unsigned int size)
Definition bytestream.h:180
static av_always_inline int bytestream2_get_bytes_left(const GetByteContext *g)
Definition bytestream.h:158
static av_always_inline unsigned int bytestream2_copy_buffer(PutByteContext *p, GetByteContext *g, unsigned int size)
Definition bytestream.h:347
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition bytestream.h:137
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition bytestream.h:168
static av_always_inline unsigned int bytestream2_put_buffer(PutByteContext *p, const uint8_t *src, unsigned int size)
Definition bytestream.h:286
#define ENC
Definition caca.c:198
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define rnd
Definition checkasm.h:135
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVPacket * pkt
@ STATE_START
Definition dirac_vlc.c:25
enum AVCodecID id
Definition dts2pts.c:607
channel
Use these values when setting the channel map with ebur128_set_channel().
Definition ebur128.h:39
double value
Definition eval.c:102
FLV common header.
@ FLV_TAG_TYPE_META
Definition flv.h:68
@ FLV_HEADER_FLAG_HASVIDEO
Definition flv.h:61
@ FLV_HEADER_FLAG_HASAUDIO
Definition flv.h:62
@ AMF_DATA_TYPE_NUMBER
Definition flv.h:168
@ AMF_DATA_TYPE_MIXEDARRAY
Definition flv.h:175
@ AMF_DATA_TYPE_STRING
Definition flv.h:170
#define AMF_END_OF_OBJECT
Definition flv.h:53
#define fail
Definition test.h:479
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_BINARY
Underlying C type is a uint8_t* that is either NULL or points to an array allocated with the av_mallo...
Definition opt.h:285
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
void av_url_split(char *proto, int proto_size, char *authorization, int authorization_size, char *hostname, int hostname_size, int *port_ptr, char *path, int path_size, const char *url)
Split a URL string into components.
Definition utils.c:361
char * av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
Encode data to base64 and null-terminate.
Definition base64.c:147
#define AV_BASE64_SIZE(x)
Calculate the output size needed to base64-encode x bytes to a null-terminated string.
Definition base64.h:66
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition dict.c:86
#define AV_DICT_MATCH_CASE
Only get an entry with exact-case key match.
Definition dict.h:74
#define AVERROR_UNKNOWN
Unknown error, typically from an external library.
Definition error.h:73
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition error.h:64
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition log.h:236
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
#define AV_LOG_VERBOSE
Detailed information.
Definition log.h:226
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
void av_md5_init(AVMD5 *ctx)
Initialize MD5 hashing.
Definition md5.c:143
void av_md5_final(AVMD5 *ctx, uint8_t *dst)
Finish hashing and output digest value.
Definition md5.c:188
struct AVMD5 * av_md5_alloc(void)
Allocate an AVMD5 context.
Definition md5.c:50
void av_md5_update(AVMD5 *ctx, const uint8_t *src, size_t len)
Update hash value.
Definition md5.c:153
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition mem.c:188
int av_reallocp_array(void *ptr, size_t nmemb, size_t size)
Allocate, reallocate an array through a pointer to a pointer.
Definition mem.c:225
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes,...
Definition avstring.c:95
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition avstring.c:85
int av_opt_set_bin(void *obj, const char *name, const uint8_t *val, int len, int search_flags)
Definition opt.c:951
int index
Definition gxfenc.c:90
cl_device_type type
static av_always_inline uint64_t av_double2int(double f)
Reinterpret a double as a 64-bit integer.
Definition intfloat.h:70
#define AV_WB32(p, v)
#define AV_RB32(p)
#define AV_RB16(p)
static const char signature[]
Definition ipmovie.c:592
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition lfg.c:32
static unsigned int av_lfg_get(AVLFG *c)
Get the next random unsigned 32-bit number using an ALFG.
Definition lfg.h:53
unsigned offset
Definition libaomenc.c:763
char * ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase)
Write hexadecimal string corresponding to given binary data.
Definition utils.c:464
Libavformat version macros.
#define LIBAVFORMAT_IDENT
Definition version.h:45
#define DEC
Definition librsvgdec.c:149
const char * desc
Definition libsvtav1.c:83
#define FFMIN(a, b)
Definition macros.h:49
Public header for MD5 hash function implementation.
Memory handling functions.
const char data[16]
Definition mxf.c:149
#define av_strdup(s)
Definition ops_static.c:55
#define av_realloc(p, s)
Definition ops_static.c:54
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
const char * name
Definition qsvenc.c:142
#define RTMP_CLIENT_VER4
Definition rtmp.h:40
#define RTMP_CLIENT_VER3
Definition rtmp.h:39
int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, const uint8_t *key, int keylen, uint8_t *dst)
Calculate HMAC-SHA2 digest for RTMP handshake packets.
Definition rtmpdigest.c:34
#define RTMP_CLIENT_PLATFORM
emulated Flash client version - 9.0.124.2 on Linux
Definition rtmp.h:36
#define RTMP_CLIENT_VER1
Definition rtmp.h:37
#define RTMP_CLIENT_VER2
Definition rtmp.h:38
#define RTMP_DEFAULT_PORT
Definition rtmp.h:27
#define RTMPS_DEFAULT_PORT
Definition rtmp.h:28
#define RTMP_HANDSHAKE_PACKET_SIZE
Definition rtmp.h:30
int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val, int add_val)
Calculate digest position for RTMP handshake packets.
Definition rtmpdigest.c:57
int ff_rtmpe_gen_pub_key(URLContext *h, uint8_t *buf)
Initialize the Diffie-Hellmann context and generate the public key.
Definition rtmpcrypt.c:122
int ff_rtmpe_compute_secret_key(URLContext *h, const uint8_t *serverdata, const uint8_t *clientdata, int type)
Compute the shared secret key and initialize the RC4 encryption.
Definition rtmpcrypt.c:145
void ff_rtmpe_encrypt_sig(URLContext *h, uint8_t *sig, const uint8_t *digest, int type)
Encrypt the signature.
Definition rtmpcrypt.c:207
int ff_rtmpe_update_keystream(URLContext *h)
Update the keystream and set RC4 keys for encryption.
Definition rtmpcrypt.c:223
void ff_amf_write_string(uint8_t **dst, const char *str)
Write string in AMF format to buffer.
Definition rtmppkt.c:51
void ff_amf_write_null(uint8_t **dst)
Write AMF NULL value to buffer.
Definition rtmppkt.c:71
void ff_amf_write_number(uint8_t **dst, double val)
Write number in AMF format to buffer.
Definition rtmppkt.c:39
int ff_rtmp_packet_read(URLContext *h, RTMPPacket *p, int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt)
Read RTMP packet sent by the server.
Definition rtmppkt.c:159
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int chunk_size, RTMPPacket **prev_pkt_ptr, int *nb_prev_pkt)
Send RTMP packet to the server.
Definition rtmppkt.c:313
void ff_amf_write_object_start(uint8_t **dst)
Write marker for AMF object to buffer.
Definition rtmppkt.c:76
void ff_amf_write_string2(uint8_t **dst, const char *str1, const char *str2)
Write a string consisting of two parts in AMF format to a buffer.
Definition rtmppkt.c:58
int ff_amf_get_string(GetByteContext *bc, uint8_t *str, int strsize, int *length)
Get AMF string value.
Definition rtmppkt.c:105
int ff_rtmp_check_alloc_array(RTMPPacket **prev_pkt, int *nb_prev_pkt, int channel)
Enlarge the prev_pkt array to fit the given channel.
Definition rtmppkt.c:138
int ff_rtmp_packet_read_internal(URLContext *h, RTMPPacket *p, int chunk_size, RTMPPacket **prev_pkt, int *nb_prev_pkt, uint8_t hdr)
Read internal RTMP packet sent by the server.
Definition rtmppkt.c:298
int ff_amf_read_null(GetByteContext *bc)
Read AMF NULL value.
Definition rtmppkt.c:131
void ff_amf_write_array_start(uint8_t **dst, uint32_t length)
Write marker and length for AMF array to buffer.
Definition rtmppkt.c:45
int ff_amf_tag_size(const uint8_t *data, const uint8_t *data_end)
Calculate number of bytes taken by first AMF entry in data.
Definition rtmppkt.c:501
void ff_amf_write_bool(uint8_t **dst, int val)
Write boolean value in AMF format to buffer.
Definition rtmppkt.c:33
int ff_amf_get_field_value(const uint8_t *data, const uint8_t *data_end, const uint8_t *name, uint8_t *dst, int dst_size)
Retrieve value of given AMF object field in string form.
Definition rtmppkt.c:569
int ff_rtmp_packet_create(RTMPPacket *pkt, int channel_id, RTMPPacketType type, int timestamp, int size)
Create new RTMP packet with given attributes.
Definition rtmppkt.c:416
void ff_rtmp_packet_destroy(RTMPPacket *pkt)
Free RTMP packet.
Definition rtmppkt.c:434
int ff_amf_match_string(const uint8_t *data, int size, const char *str)
Match AMF string with a NULL-terminated string.
Definition rtmppkt.c:708
void ff_amf_write_object_end(uint8_t **dst)
Write marker for end of AMF object to buffer.
Definition rtmppkt.c:87
void ff_amf_write_field_name(uint8_t **dst, const char *str)
Write string used as field name in AMF object to buffer.
Definition rtmppkt.c:81
int ff_amf_read_string(GetByteContext *bc, uint8_t *str, int strsize, int *length)
Read AMF string value.
Definition rtmppkt.c:123
int ff_amf_read_number(GetByteContext *bc, double *val)
Read AMF number value.
Definition rtmppkt.c:95
@ RTMP_AUDIO_CHANNEL
channel for audio data
Definition rtmppkt.h:39
@ RTMP_NETWORK_CHANNEL
channel for network-related messages (bandwidth report, ping, etc)
Definition rtmppkt.h:37
@ RTMP_VIDEO_CHANNEL
channel for video data
Definition rtmppkt.h:40
@ RTMP_SYSTEM_CHANNEL
channel for sending server control messages
Definition rtmppkt.h:38
@ RTMP_SOURCE_CHANNEL
channel for a/v invokes
Definition rtmppkt.h:41
void ff_rtmp_packet_dump(void *ctx, RTMPPacket *p)
Print information and contents of RTMP packet.
@ RTMP_PT_USER_CONTROL
user control
Definition rtmppkt.h:50
@ RTMP_PT_NOTIFY
some notification
Definition rtmppkt.h:58
@ RTMP_PT_CHUNK_SIZE
chunk size change
Definition rtmppkt.h:48
@ RTMP_PT_INVOKE
invoke some stream action
Definition rtmppkt.h:60
@ RTMP_PT_BYTES_READ
number of bytes read
Definition rtmppkt.h:49
@ RTMP_PT_SET_PEER_BW
peer bandwidth
Definition rtmppkt.h:52
@ RTMP_PT_WINDOW_ACK_SIZE
window acknowledgement size
Definition rtmppkt.h:51
@ RTMP_PT_VIDEO
video packet
Definition rtmppkt.h:54
@ RTMP_PT_METADATA
FLV metadata.
Definition rtmppkt.h:61
@ RTMP_PT_AUDIO
audio packet
Definition rtmppkt.h:53
static int handle_notify(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:2333
static const AVOption rtmp_options[]
Definition rtmpproto.c:3205
static int rtmp_read(URLContext *s, uint8_t *buf, int size)
Definition rtmpproto.c:2992
static int read_number_result(RTMPPacket *pkt, double *number)
Read the AMF_NUMBER response ("_result") to a function call (e.g.
Definition rtmpproto.c:2102
static int rtmp_calc_swfhash(URLContext *s)
Definition rtmpproto.c:1173
static int gen_buffer_time(URLContext *s, RTMPContext *rt)
Generate client buffer time and send it to the server.
Definition rtmpproto.c:805
#define SERVER_KEY_OPEN_PART_LEN
length of partial key used for first server digest signing
Definition rtmpproto.c:150
static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1984
static int gen_publish(URLContext *s, RTMPContext *rt)
Generate 'publish' call and send it to the server.
Definition rtmpproto.c:904
static int gen_seek(URLContext *s, RTMPContext *rt, int64_t timestamp)
Definition rtmpproto.c:851
static int rtmp_send_hs_packet(RTMPContext *rt, uint32_t first_int, uint32_t second_int, char *arraydata, int size)
Definition rtmpproto.c:1481
static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1575
static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1635
static int gen_get_stream_length(URLContext *s, RTMPContext *rt)
Generate 'getStreamLength' call and send it to the server.
Definition rtmpproto.c:783
static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1875
static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset, char **tracked_method)
Definition rtmpproto.c:203
static const uint8_t rtmp_server_key[]
Key used for RTMP server digest signing.
Definition rtmpproto.c:152
static int rtmp_close(URLContext *h)
Definition rtmpproto.c:2589
static int read_connect(URLContext *s, RTMPContext *rt)
Definition rtmpproto.c:472
static int add_tracked_method(RTMPContext *rt, const char *name, int id)
Definition rtmpproto.c:173
static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
rtmp handshake server side
Definition rtmpproto.c:1501
#define FLASHVER_MAX_LENGTH
Definition rtmpproto.c:56
static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
Definition rtmpproto.c:267
static int inject_fake_duration_metadata(RTMPContext *rt)
Insert a fake onMetadata packet into the FLV stream to notify the FLV demuxer about the duration of t...
Definition rtmpproto.c:2625
static int write_begin(URLContext *s)
Definition rtmpproto.c:1914
static int rtmp_receive_hs_packet(RTMPContext *rt, uint32_t *first_int, uint32_t *second_int, char *arraydata, int size)
Definition rtmpproto.c:1460
#define RTMP_HEADER
Definition rtmpproto.c:58
static int gen_swf_verification(URLContext *s, RTMPContext *rt)
Generate SWF verification message and send it to the server.
Definition rtmpproto.c:957
static int handle_invoke(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:2241
static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
Definition rtmpproto.c:1727
static int gen_release_stream(URLContext *s, RTMPContext *rt)
Generate 'releaseStream' call and send it to the server.
Definition rtmpproto.c:660
static int rtmp_pause(void *opaque, int pause)
Definition rtmpproto.c:3040
static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
Generate report on bytes read so far and send it to the server.
Definition rtmpproto.c:1018
static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
Definition rtmpproto.c:2296
static int gen_create_stream(URLContext *s, RTMPContext *rt)
Generate 'createStream' call and send it to the server.
Definition rtmpproto.c:732
static int handle_connect_error(URLContext *s, const char *desc)
Definition rtmpproto.c:1784
static int64_t rtmp_seek(void *opaque, int stream_index, int64_t timestamp, int flags)
Definition rtmpproto.c:3019
static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1662
ClientState
RTMP protocol handler state.
Definition rtmpproto.c:61
@ STATE_STOPPED
the broadcast has been stopped
Definition rtmpproto.c:70
@ STATE_SENDING
received a play command (for output)
Definition rtmpproto.c:69
@ STATE_PUBLISHING
client has started sending multimedia data to server (for output)
Definition rtmpproto.c:67
@ STATE_HANDSHAKED
client has performed handshake
Definition rtmpproto.c:63
@ STATE_RECEIVING
received a publish command (for input)
Definition rtmpproto.c:68
@ STATE_SEEKING
client has started the seek operation. Back on STATE_PLAYING when the time comes
Definition rtmpproto.c:66
@ STATE_FCPUBLISH
client FCPublishing stream (for output)
Definition rtmpproto.c:64
@ STATE_PLAYING
client has started receiving multimedia data from server
Definition rtmpproto.c:65
static const uint8_t rtmp_player_key[]
Client key used for digest signing.
Definition rtmpproto.c:141
static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
Parse received packet and possibly perform some action depending on the packet contents.
Definition rtmpproto.c:2396
static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt, const char *opaque, const char *challenge)
Definition rtmpproto.c:1688
static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:2132
static int get_packet(URLContext *s, int for_header)
Interact with the server by receiving and sending RTMP packets until there is some significant data (...
Definition rtmpproto.c:2504
#define RTMP_CTRL_ABORT_MESSAGE
Definition rtmpproto.c:470
static size_t zstrlen(const char *c)
Definition rtmpproto.c:166
static int gen_check_bw(URLContext *s, RTMPContext *rt)
Generate check bandwidth message and send it to the server.
Definition rtmpproto.c:997
static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
Generate window acknowledgement size message and send it to the server.
Definition rtmpproto.c:978
#define APP_MAX_LENGTH
Definition rtmpproto.c:54
static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
Generate ping reply and send it to the server.
Definition rtmpproto.c:931
static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
Put HMAC-SHA2 digest of packet data (except for the bytes where this digest will be stored) into that...
Definition rtmpproto.c:1062
static void free_tracked_methods(RTMPContext *rt)
Definition rtmpproto.c:228
static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt, const char *subscribe)
Definition rtmpproto.c:1034
static void del_tracked_method(RTMPContext *rt, int index)
Definition rtmpproto.c:196
static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt, uint8_t *buf)
Definition rtmpproto.c:1105
static int gen_delete_stream(URLContext *s, RTMPContext *rt)
Generate 'deleteStream' call and send it to the server.
Definition rtmpproto.c:757
static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
Generate 'FCUnpublish' call and send it to the server.
Definition rtmpproto.c:708
static int gen_connect(URLContext *s, RTMPContext *rt)
Generate 'connect' call and send it to the server.
Definition rtmpproto.c:330
static int rtmp_handshake(URLContext *s, RTMPContext *rt)
Perform handshake with the server by means of exchanging pseudorandom data signed with HMAC-SHA2 dige...
Definition rtmpproto.c:1264
#define RTMP_PKTDATA_DEFAULT_SIZE
Definition rtmpproto.c:57
static int write_status(URLContext *s, RTMPPacket *pkt, const char *status, const char *description, const char *details)
Definition rtmpproto.c:1940
static int update_offset(RTMPContext *rt, int size)
Definition rtmpproto.c:2272
#define OFFSET(x)
Definition rtmpproto.c:3201
static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
Definition rtmpproto.c:239
static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
Generate 'FCPublish' call and send it to the server.
Definition rtmpproto.c:684
static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
Open RTMP connection and verify that the stream can be played.
Definition rtmpproto.c:2688
static int gen_play(URLContext *s, RTMPContext *rt)
Generate 'play' call and send it to the server, then ping the server to start actual playing.
Definition rtmpproto.c:827
static int gen_pause(URLContext *s, RTMPContext *rt, int pause, uint32_t timestamp)
Generate a pause packet that either pauses or unpauses the current stream.
Definition rtmpproto.c:877
#define TCURL_MAX_LENGTH
Definition rtmpproto.c:55
static int rtmp_validate_digest(uint8_t *buf, int off)
Verify that the received server response has the expected digest value.
Definition rtmpproto.c:1087
static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:2204
static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
Definition rtmpproto.c:2441
#define PLAYER_KEY_OPEN_PART_LEN
length of partial key used for first client digest signing
Definition rtmpproto.c:139
static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
Definition rtmpproto.c:3055
static int handle_user_control(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1608
#define RTMP_PROTOCOL(flavor, uppercase)
Definition rtmpproto.c:3256
static const uint8_t header[24]
Definition sdr2.c:68
#define snprintf
Definition snprintf.h:34
double strtod(const char *, char **)
Describe the class of an AVClass context structure.
Definition log.h:76
Context structure for the Lagged Fibonacci PRNG.
Definition lfg.h:33
Definition md5.c:42
AVOption.
Definition opt.h:428
const uint8_t * buffer_end
Definition bytestream.h:34
const uint8_t * buffer
Definition bytestream.h:34
protocol handler context
Definition rtmpproto.c:79
RTMPPacket * prev_pkt[2]
packet history used when reading and sending packets ([0] for reading, [1] for writing)
Definition rtmpproto.c:82
int nb_streamid
The next stream id to return on createStream calls.
Definition rtmpproto.c:128
int encrypted
use an encrypted connection (RTMPE only)
Definition rtmpproto.c:122
char * swfverify
URL to player swf file, compute hash/size automatically.
Definition rtmpproto.c:115
int has_video
presence of video data
Definition rtmpproto.c:104
RTMPPacket out_pkt
rtmp packet, created from flv a/v or metadata (for output)
Definition rtmpproto.c:97
uint64_t bytes_read
number of bytes read from server
Definition rtmpproto.c:99
TrackedMethod * tracked_methods
tracked methods buffer
Definition rtmpproto.c:123
uint8_t * flv_data
buffer with data for demuxer
Definition rtmpproto.c:93
int listen_timeout
listen timeout to wait for new connections
Definition rtmpproto.c:127
int swfsize
size of the decompressed SWF file
Definition rtmpproto.c:113
int max_sent_unacked
max unacked sent bytes
Definition rtmpproto.c:119
int nb_prev_pkt[2]
number of elements in prev_pkt
Definition rtmpproto.c:83
char * conn
append arbitrary AMF data to the Connect message
Definition rtmpproto.c:90
char * pageurl
url of the web page
Definition rtmpproto.c:117
int client_buffer_time
client buffer time in ms
Definition rtmpproto.c:120
int skip_bytes
number of bytes to skip from the input FLV stream in the next write call
Definition rtmpproto.c:102
char * playpath
stream identifier to play (with possible "mp4:" prefix)
Definition rtmpproto.c:87
int received_metadata
Indicates if we have received metadata about the streams.
Definition rtmpproto.c:105
char password[50]
Definition rtmpproto.c:133
char * flashver
version of the flash plugin
Definition rtmpproto.c:110
int is_input
input/output flag
Definition rtmpproto.c:86
int nb_tracked_methods
number of tracked methods
Definition rtmpproto.c:124
int flv_off
number of bytes read from current buffer
Definition rtmpproto.c:95
uint8_t flv_header[RTMP_HEADER]
partial incoming flv packet header
Definition rtmpproto.c:106
char * app
name of application
Definition rtmpproto.c:89
char * enhanced_codecs
codec list in enhanced rtmp
Definition rtmpproto.c:131
uint64_t last_bytes_read
number of bytes read last reported to server
Definition rtmpproto.c:100
char * swfurl
url of the swf player
Definition rtmpproto.c:114
int out_chunk_size
size of the chunks outgoing RTMP packets are divided into
Definition rtmpproto.c:85
int flv_nb_packets
number of flv packets published
Definition rtmpproto.c:96
int stream_id
ID assigned by the server for the stream.
Definition rtmpproto.c:92
int flush_interval
number of packets flushed in the same request (RTMPT only)
Definition rtmpproto.c:121
int listen
listen mode flag
Definition rtmpproto.c:126
int tcp_nodelay
Use TCP_NODELAY to disable Nagle's algorithm if set to 1.
Definition rtmpproto.c:130
int has_audio
presence of audio data
Definition rtmpproto.c:103
char swfverification[42]
hash of the SWF verification
Definition rtmpproto.c:116
double duration
Duration of the stream in seconds as returned by the server (only valid if non-zero)
Definition rtmpproto.c:129
int flv_header_bytes
number of initialized bytes in flv_header
Definition rtmpproto.c:107
int flv_size
current buffer size
Definition rtmpproto.c:94
int tracked_methods_size
size of the tracked methods buffer
Definition rtmpproto.c:125
ClientState state
current state
Definition rtmpproto.c:91
int in_chunk_size
size of the chunks incoming RTMP packets are divided into
Definition rtmpproto.c:84
char * tcurl
url of the target stream
Definition rtmpproto.c:109
uint32_t receive_report_size
number of bytes after which we should report the number of received bytes to the peer
Definition rtmpproto.c:98
char auth_params[500]
Definition rtmpproto.c:134
int nb_invokes
keeps track of invoke messages
Definition rtmpproto.c:108
char * subscribe
name of live stream to subscribe
Definition rtmpproto.c:118
URLContext * stream
TCP stream used in interactions with RTMP server.
Definition rtmpproto.c:81
int swfhash_len
length of the SHA256 hash
Definition rtmpproto.c:112
int do_reconnect
Definition rtmpproto.c:135
int live
0: recorded, -1: live, -2: both
Definition rtmpproto.c:88
char * swfhash
SHA256 hash of the decompressed SWF file (32 bytes)
Definition rtmpproto.c:111
uint32_t last_timestamp
last timestamp received in a packet
Definition rtmpproto.c:101
char username[50]
Definition rtmpproto.c:132
structure for holding RTMP packets
Definition rtmppkt.h:77
int size
packet payload size
Definition rtmppkt.h:84
uint32_t extra
probably an additional channel ID used during streaming data
Definition rtmppkt.h:82
RTMPPacketType type
packet payload type
Definition rtmppkt.h:79
uint32_t timestamp
packet full timestamp
Definition rtmppkt.h:80
uint8_t * data
packet payload
Definition rtmppkt.h:83
int channel_id
RTMP channel ID (nothing to do with audio/video channels though)
Definition rtmppkt.h:78
char * name
Definition rtmpproto.c:74
int max_packet_size
if non zero, the stream is packetized with this max packet size
Definition url.h:41
int flags
Definition url.h:40
uint8_t level
Definition svq3.c:208
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
static const uint8_t encrypted[]
Definition aes_ctr.c:34
static char buffer[20]
Definition seek.c:32
static int64_t pts
int size
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition url.c:40
unbuffered private I/O API
static int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h.
Definition url.h:224
static int ffurl_write(URLContext *h, const uint8_t *buf, int size)
Write size bytes from buf to the resource accessed by h.
Definition url.h:204
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition url.h:183
uint32_t fourcc
static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
else temp
Definition vf_mcdeint.c:275
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord, int maxc)
static void copy(const float *p1, float *p2, const int length)
int len
static double c[64]