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 (;;) {
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
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
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) {
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) {
1206 goto fail;
1207 }
1208
1209 if (!memcmp(in_data, "CWS", 3)) {
1210#if CONFIG_ZLIB
1212 if (in_size < 8) {
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
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
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. */
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 av_md5_update(md5, nonce, strlen(nonce));
1764 av_md5_update(md5, ":", 1);
1765 av_md5_update(md5, nc, strlen(nc));
1766 av_md5_update(md5, ":", 1);
1767 av_md5_update(md5, cnonce, strlen(cnonce));
1768 av_md5_update(md5, ":", 1);
1769 av_md5_update(md5, qop, strlen(qop));
1770 av_md5_update(md5, ":", 1);
1771 av_md5_update(md5, hashstr2, strlen(hashstr2));
1773 ff_data_to_hex(hashstr1, hash, 16, 1);
1774
1775 snprintf(rt->auth_params, sizeof(rt->auth_params),
1776 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1777 "llnw", user, nonce, cnonce, nc, hashstr1);
1778
1779 av_free(md5);
1780 return 0;
1781}
1782
1783static int handle_connect_error(URLContext *s, const char *desc)
1784{
1785 RTMPContext *rt = s->priv_data;
1786 char buf[300], *ptr, authmod[15];
1787 int i = 0, ret = 0;
1788 const char *user = "", *salt = "", *opaque = NULL,
1789 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1790
1791 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1792 !(cptr = strstr(desc, "authmod=llnw"))) {
1794 "Unknown connect error (unsupported authentication method?)\n");
1795 return AVERROR_UNKNOWN;
1796 }
1797 cptr += strlen("authmod=");
1798 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1799 authmod[i++] = *cptr++;
1800 authmod[i] = '\0';
1801
1802 if (!rt->username[0] || !rt->password[0]) {
1803 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1804 return AVERROR_UNKNOWN;
1805 }
1806
1807 if (strstr(desc, "?reason=authfailed")) {
1808 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1809 return AVERROR_UNKNOWN;
1810 } else if (strstr(desc, "?reason=nosuchuser")) {
1811 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1812 return AVERROR_UNKNOWN;
1813 }
1814
1815 if (rt->auth_tried) {
1816 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1817 return AVERROR_UNKNOWN;
1818 }
1819
1820 rt->auth_params[0] = '\0';
1821
1822 if (strstr(desc, "code=403 need auth")) {
1823 snprintf(rt->auth_params, sizeof(rt->auth_params),
1824 "?authmod=%s&user=%s", authmod, rt->username);
1825 return 0;
1826 }
1827
1828 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1829 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1830 return AVERROR_UNKNOWN;
1831 }
1832
1833 av_strlcpy(buf, cptr + 1, sizeof(buf));
1834 ptr = buf;
1835
1836 while (ptr) {
1837 char *next = strchr(ptr, '&');
1838 char *value = strchr(ptr, '=');
1839 if (next)
1840 *next++ = '\0';
1841 if (value) {
1842 *value++ = '\0';
1843 if (!strcmp(ptr, "user")) {
1844 user = value;
1845 } else if (!strcmp(ptr, "salt")) {
1846 salt = value;
1847 } else if (!strcmp(ptr, "opaque")) {
1848 opaque = value;
1849 } else if (!strcmp(ptr, "challenge")) {
1850 challenge = value;
1851 } else if (!strcmp(ptr, "nonce")) {
1852 nonce = value;
1853 } else {
1854 av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1855 }
1856 } else {
1857 av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1858 }
1859 ptr = next;
1860 }
1861
1862 if (!strcmp(authmod, "adobe")) {
1863 if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1864 return ret;
1865 } else {
1866 if (!nonce) {
1867 av_log(s, AV_LOG_ERROR, "No nonce in the llnw authentication challenge\n");
1868 return AVERROR_UNKNOWN;
1869 }
1870 if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1871 return ret;
1872 }
1873
1874 rt->auth_tried = 1;
1875 return 0;
1876}
1877
1879{
1880 RTMPContext *rt = s->priv_data;
1881 const uint8_t *data_end = pkt->data + pkt->size;
1882 char *tracked_method = NULL;
1883 int level = AV_LOG_ERROR;
1884 uint8_t tmpstr[256];
1885 int ret;
1886
1887 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1888 return ret;
1889
1890 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1891 "description", tmpstr, sizeof(tmpstr))) {
1892 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1893 !strcmp(tracked_method, "releaseStream") ||
1894 !strcmp(tracked_method, "FCSubscribe") ||
1895 !strcmp(tracked_method, "FCPublish"))) {
1896 /* Gracefully ignore Adobe-specific historical artifact errors. */
1898 ret = 0;
1899 } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1901 ret = 0;
1902 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1903 ret = handle_connect_error(s, tmpstr);
1904 if (!ret) {
1905 rt->do_reconnect = 1;
1907 }
1908 } else
1910 av_log(s, level, "Server error: %s\n", tmpstr);
1911 }
1912
1913 av_free(tracked_method);
1914 return ret;
1915}
1916
1918{
1919 RTMPContext *rt = s->priv_data;
1920 PutByteContext pbc;
1921 RTMPPacket spkt = { 0 };
1922 int ret;
1923
1924 // Send Stream Begin 1
1926 RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
1927 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1928 return ret;
1929 }
1930
1931 bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1932 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1933 bytestream2_put_be32(&pbc, rt->nb_streamid);
1934
1936 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1937
1939
1940 return ret;
1941}
1942
1944 const char *status, const char *description, const char *details)
1945{
1946 RTMPContext *rt = s->priv_data;
1947 RTMPPacket spkt = { 0 };
1948 uint8_t *pp;
1949 int ret;
1950
1952 RTMP_PT_INVOKE, 0,
1954 + strlen(status) + strlen(description)
1955 + zstrlen(details))) < 0) {
1956 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1957 return ret;
1958 }
1959
1960 pp = spkt.data;
1961 spkt.extra = pkt->extra;
1962 ff_amf_write_string(&pp, "onStatus");
1963 ff_amf_write_number(&pp, 0);
1964 ff_amf_write_null(&pp);
1965
1967 ff_amf_write_field_name(&pp, "level");
1968 ff_amf_write_string(&pp, "status");
1969 ff_amf_write_field_name(&pp, "code");
1970 ff_amf_write_string(&pp, status);
1971 ff_amf_write_field_name(&pp, "description");
1972 ff_amf_write_string(&pp, description);
1973 if (details) {
1974 ff_amf_write_field_name(&pp, "details");
1975 ff_amf_write_string(&pp, details);
1976 }
1978
1979 spkt.size = pp - spkt.data;
1981 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1983
1984 return ret;
1985}
1986
1988{
1989 RTMPContext *rt = s->priv_data;
1990 double seqnum;
1991 char filename[128];
1992 char command[64];
1993 int stringlen;
1994 char *pchar;
1995 const uint8_t *p = pkt->data;
1996 uint8_t *pp = NULL;
1997 RTMPPacket spkt = { 0 };
1998 GetByteContext gbc;
1999 int ret;
2000
2001 bytestream2_init(&gbc, p, pkt->size);
2002 if (ff_amf_read_string(&gbc, command, sizeof(command),
2003 &stringlen)) {
2004 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
2005 return AVERROR_INVALIDDATA;
2006 }
2007
2008 ret = ff_amf_read_number(&gbc, &seqnum);
2009 if (ret)
2010 return ret;
2011 ret = ff_amf_read_null(&gbc);
2012 if (ret)
2013 return ret;
2014 if (!strcmp(command, "FCPublish") ||
2015 !strcmp(command, "publish")) {
2016 ret = ff_amf_read_string(&gbc, filename,
2017 sizeof(filename), &stringlen);
2018 if (ret) {
2019 if (ret == AVERROR(EINVAL))
2020 av_log(s, AV_LOG_ERROR, "Unable to parse stream name - name too long?\n");
2021 else
2022 av_log(s, AV_LOG_ERROR, "Unable to parse stream name\n");
2023 return ret;
2024 }
2025 // check with url
2026 if (s->filename) {
2027 pchar = strrchr(s->filename, '/');
2028 if (!pchar) {
2030 "Unable to find / in url %s, bad format\n",
2031 s->filename);
2032 pchar = s->filename;
2033 }
2034 pchar++;
2035 if (strcmp(pchar, filename))
2036 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
2037 " %s\n", filename, pchar);
2038 }
2039 rt->state = STATE_RECEIVING;
2040 }
2041
2042 if (!strcmp(command, "FCPublish")) {
2044 RTMP_PT_INVOKE, 0,
2046 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2047 return ret;
2048 }
2049 pp = spkt.data;
2050 ff_amf_write_string(&pp, "onFCPublish");
2051 } else if (!strcmp(command, "publish")) {
2052 char statusmsg[sizeof(filename) + 32];
2053 snprintf(statusmsg, sizeof(statusmsg), "%s is now published", filename);
2054 ret = write_begin(s);
2055 if (ret < 0)
2056 return ret;
2057
2058 // Send onStatus(NetStream.Publish.Start)
2059 return write_status(s, pkt, "NetStream.Publish.Start",
2060 statusmsg, filename);
2061 } else if (!strcmp(command, "play")) {
2062 ret = write_begin(s);
2063 if (ret < 0)
2064 return ret;
2065 rt->state = STATE_SENDING;
2066 return write_status(s, pkt, "NetStream.Play.Start",
2067 "playing stream", NULL);
2068 } else {
2070 RTMP_PT_INVOKE, 0,
2072 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
2073 return ret;
2074 }
2075 pp = spkt.data;
2076 ff_amf_write_string(&pp, "_result");
2077 ff_amf_write_number(&pp, seqnum);
2078 ff_amf_write_null(&pp);
2079 if (!strcmp(command, "createStream")) {
2080 rt->nb_streamid++;
2081 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
2082 rt->nb_streamid++; /* Values 0 and 2 are reserved */
2084 /* By now we don't control which streams are removed in
2085 * deleteStream. There is no stream creation control
2086 * if a client creates more than 2^32 - 2 streams. */
2087 }
2088 }
2089 spkt.size = pp - spkt.data;
2091 &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
2093 return ret;
2094}
2095
2096/**
2097 * Read the AMF_NUMBER response ("_result") to a function call
2098 * (e.g. createStream()). This response should be made up of the AMF_STRING
2099 * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2100 * successful response, we will return set the value to number (otherwise number
2101 * will not be changed).
2102 *
2103 * @return 0 if reading the value succeeds, negative value otherwise
2104 */
2105static int read_number_result(RTMPPacket *pkt, double *number)
2106{
2107 // We only need to fit "_result" in this.
2108 uint8_t strbuffer[8];
2109 int stringlen;
2110 double numbuffer;
2111 GetByteContext gbc;
2112
2113 bytestream2_init(&gbc, pkt->data, pkt->size);
2114
2115 // Value 1/4: "_result" as AMF_STRING
2116 if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2117 return AVERROR_INVALIDDATA;
2118 if (strcmp(strbuffer, "_result"))
2119 return AVERROR_INVALIDDATA;
2120 // Value 2/4: The callee reference number
2121 if (ff_amf_read_number(&gbc, &numbuffer))
2122 return AVERROR_INVALIDDATA;
2123 // Value 3/4: Null
2124 if (ff_amf_read_null(&gbc))
2125 return AVERROR_INVALIDDATA;
2126 // Value 4/4: The response as AMF_NUMBER
2127 if (ff_amf_read_number(&gbc, &numbuffer))
2128 return AVERROR_INVALIDDATA;
2129 else
2130 *number = numbuffer;
2131
2132 return 0;
2133}
2134
2136{
2137 RTMPContext *rt = s->priv_data;
2138 char *tracked_method = NULL;
2139 int ret = 0;
2140
2141 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2142 return ret;
2143
2144 if (!tracked_method) {
2145 /* Ignore this reply when the current method is not tracked. */
2146 return ret;
2147 }
2148
2149 if (!strcmp(tracked_method, "connect")) {
2150 if (!rt->is_input) {
2151 if ((ret = gen_release_stream(s, rt)) < 0)
2152 goto fail;
2153
2154 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2155 goto fail;
2156 } else {
2157 if ((ret = gen_window_ack_size(s, rt)) < 0)
2158 goto fail;
2159 }
2160
2161 if ((ret = gen_create_stream(s, rt)) < 0)
2162 goto fail;
2163
2164 if (rt->is_input) {
2165 /* Send the FCSubscribe command when the name of live
2166 * stream is defined by the user or if it's a live stream. */
2167 if (rt->subscribe) {
2168 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2169 goto fail;
2170 } else if (rt->live == -1) {
2171 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2172 goto fail;
2173 }
2174 }
2175 } else if (!strcmp(tracked_method, "createStream")) {
2176 double stream_id;
2177 if (read_number_result(pkt, &stream_id)) {
2178 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2179 } else {
2180 rt->stream_id = stream_id;
2181 }
2182
2183 if (!rt->is_input) {
2184 if ((ret = gen_publish(s, rt)) < 0)
2185 goto fail;
2186 } else {
2187 if (rt->live != -1) {
2188 if ((ret = gen_get_stream_length(s, rt)) < 0)
2189 goto fail;
2190 }
2191 if ((ret = gen_play(s, rt)) < 0)
2192 goto fail;
2193 if ((ret = gen_buffer_time(s, rt)) < 0)
2194 goto fail;
2195 }
2196 } else if (!strcmp(tracked_method, "getStreamLength")) {
2197 if (read_number_result(pkt, &rt->duration)) {
2198 av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2199 }
2200 }
2201
2202fail:
2203 av_free(tracked_method);
2204 return ret;
2205}
2206
2208{
2209 RTMPContext *rt = s->priv_data;
2210 const uint8_t *data_end = pkt->data + pkt->size;
2211 const uint8_t *ptr = pkt->data + RTMP_HEADER;
2212 uint8_t tmpstr[256];
2213 int i, t;
2214
2215 for (i = 0; i < 2; i++) {
2216 t = ff_amf_tag_size(ptr, data_end);
2217 if (t < 0)
2218 return 1;
2219 ptr += t;
2220 }
2221
2222 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2223 if (!t && !strcmp(tmpstr, "error")) {
2224 t = ff_amf_get_field_value(ptr, data_end,
2225 "description", tmpstr, sizeof(tmpstr));
2226 if (t || !tmpstr[0])
2227 t = ff_amf_get_field_value(ptr, data_end, "code",
2228 tmpstr, sizeof(tmpstr));
2229 if (!t)
2230 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2231 return -1;
2232 }
2233
2234 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2235 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2236 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2237 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2238 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2239 if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2240
2241 return 0;
2242}
2243
2245{
2246 RTMPContext *rt = s->priv_data;
2247 int ret = 0;
2248
2249 //TODO: check for the messages sent for wrong state?
2250 if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2251 if ((ret = handle_invoke_error(s, pkt)) < 0)
2252 return ret;
2253 } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2254 if ((ret = handle_invoke_result(s, pkt)) < 0)
2255 return ret;
2256 } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2257 if ((ret = handle_invoke_status(s, pkt)) < 0)
2258 return ret;
2259 } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2260 if ((ret = gen_check_bw(s, rt)) < 0)
2261 return ret;
2262 } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2263 ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2264 ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2265 ff_amf_match_string(pkt->data, pkt->size, "play") ||
2266 ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2267 ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2268 if ((ret = send_invoke_response(s, pkt)) < 0)
2269 return ret;
2270 }
2271
2272 return ret;
2273}
2274
2275static int update_offset(RTMPContext *rt, int size)
2276{
2277 int old_flv_size;
2278
2279 if (size < 0)
2280 return AVERROR(EINVAL);
2281
2282 // generate packet header and put data into buffer for FLV demuxer
2283 if (rt->flv_off < rt->flv_size) {
2284 // There is old unread data in the buffer, thus append at the end
2285 if (rt->flv_size > INT_MAX - size)
2286 return AVERROR(ERANGE);
2287 old_flv_size = rt->flv_size;
2288 rt->flv_size += size;
2289 } else {
2290 // All data has been read, write the new data at the start of the buffer
2291 old_flv_size = 0;
2292 rt->flv_size = size;
2293 rt->flv_off = 0;
2294 }
2295
2296 return old_flv_size;
2297}
2298
2300{
2301 int old_flv_size, ret;
2302 PutByteContext pbc;
2303 const uint8_t *data = pkt->data + skip;
2304 const int size = pkt->size - skip;
2305 uint32_t ts = pkt->timestamp;
2306
2307 if (pkt->type == RTMP_PT_AUDIO) {
2308 rt->has_audio = 1;
2309 } else if (pkt->type == RTMP_PT_VIDEO) {
2310 rt->has_video = 1;
2311 }
2312
2313 if (size > INT_MAX - 15)
2314 return AVERROR(ERANGE);
2315 old_flv_size = update_offset(rt, size + 15);
2316 if (old_flv_size < 0)
2317 return old_flv_size;
2318
2319 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2320 rt->flv_size = rt->flv_off = 0;
2321 return ret;
2322 }
2324 bytestream2_skip_p(&pbc, old_flv_size);
2325 bytestream2_put_byte(&pbc, pkt->type);
2326 bytestream2_put_be24(&pbc, size);
2327 bytestream2_put_be24(&pbc, ts);
2328 bytestream2_put_byte(&pbc, ts >> 24);
2329 bytestream2_put_be24(&pbc, 0);
2331 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2332
2333 return 0;
2334}
2335
2337{
2338 RTMPContext *rt = s->priv_data;
2339 uint8_t commandbuffer[64];
2340 char statusmsg[128];
2341 int stringlen, ret, skip = 0;
2342 GetByteContext gbc;
2343
2344 bytestream2_init(&gbc, pkt->data, pkt->size);
2345 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2346 &stringlen))
2347 return AVERROR_INVALIDDATA;
2348
2349 if (!strcmp(commandbuffer, "onMetaData")) {
2350 // metadata properties should be stored in a mixed array
2351 if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2352 // We have found a metaData Array so flv can determine the streams
2353 // from this.
2354 rt->received_metadata = 1;
2355 // skip 32-bit max array index
2356 bytestream2_skip(&gbc, 4);
2357 while (bytestream2_get_bytes_left(&gbc) > 3) {
2358 if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2359 &stringlen))
2360 return AVERROR_INVALIDDATA;
2361 // We do not care about the content of the property (yet).
2362 stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2363 if (stringlen < 0)
2364 return AVERROR_INVALIDDATA;
2365 bytestream2_skip(&gbc, stringlen);
2366
2367 // The presence of the following properties indicates that the
2368 // respective streams are present.
2369 if (!strcmp(statusmsg, "videocodecid")) {
2370 rt->has_video = 1;
2371 }
2372 if (!strcmp(statusmsg, "audiocodecid")) {
2373 rt->has_audio = 1;
2374 }
2375 }
2376 if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2377 return AVERROR_INVALIDDATA;
2378 }
2379 }
2380
2381 // Skip the @setDataFrame string and validate it is a notification
2382 if (!strcmp(commandbuffer, "@setDataFrame")) {
2383 skip = gbc.buffer - pkt->data;
2384 ret = ff_amf_read_string(&gbc, statusmsg,
2385 sizeof(statusmsg), &stringlen);
2386 if (ret < 0)
2387 return AVERROR_INVALIDDATA;
2388 }
2389
2390 return append_flv_data(rt, pkt, skip);
2391}
2392
2393/**
2394 * Parse received packet and possibly perform some action depending on
2395 * the packet contents.
2396 * @return 0 for no errors, negative values for serious errors which prevent
2397 * further communications, positive values for uncritical errors
2398 */
2400{
2401 int ret;
2402
2403#ifdef DEBUG
2405#endif
2406
2407 switch (pkt->type) {
2408 case RTMP_PT_BYTES_READ:
2409 av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2410 break;
2411 case RTMP_PT_CHUNK_SIZE:
2412 if ((ret = handle_chunk_size(s, pkt)) < 0)
2413 return ret;
2414 break;
2416 if ((ret = handle_user_control(s, pkt)) < 0)
2417 return ret;
2418 break;
2420 if ((ret = handle_set_peer_bw(s, pkt)) < 0)
2421 return ret;
2422 break;
2424 if ((ret = handle_window_ack_size(s, pkt)) < 0)
2425 return ret;
2426 break;
2427 case RTMP_PT_INVOKE:
2428 if ((ret = handle_invoke(s, pkt)) < 0)
2429 return ret;
2430 break;
2431 case RTMP_PT_VIDEO:
2432 case RTMP_PT_AUDIO:
2433 case RTMP_PT_METADATA:
2434 case RTMP_PT_NOTIFY:
2435 /* Audio, Video and Metadata packets are parsed in get_packet() */
2436 break;
2437 default:
2438 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2439 break;
2440 }
2441 return 0;
2442}
2443
2445{
2446 int ret, old_flv_size, type;
2447 PutByteContext pbc;
2448 GetByteContext gbc;
2449 uint32_t size;
2450 uint32_t ts, cts, pts = 0;
2451
2452 old_flv_size = update_offset(rt, pkt->size);
2453 if (old_flv_size < 0)
2454 return old_flv_size;
2455
2456 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2457 rt->flv_size = rt->flv_off = 0;
2458 return ret;
2459 }
2460
2461 bytestream2_init(&gbc, pkt->data, pkt->size);
2463 bytestream2_skip_p(&pbc, old_flv_size);
2464
2465 /* copy data while rewriting timestamps */
2466 ts = pkt->timestamp;
2467
2468 while (bytestream2_get_bytes_left(&gbc) > RTMP_HEADER) {
2469 type = bytestream2_get_byte(&gbc);
2470 size = bytestream2_get_be24(&gbc);
2471 cts = bytestream2_get_be24(&gbc);
2472 cts |= bytestream2_get_byte(&gbc) << 24;
2473 if (!pts)
2474 pts = cts;
2475 ts += cts - pts;
2476 pts = cts;
2477 if (size + 3 + 4 > bytestream2_get_bytes_left(&gbc))
2478 break;
2479 bytestream2_put_byte(&pbc, type);
2480 bytestream2_put_be24(&pbc, size);
2481 bytestream2_put_be24(&pbc, ts);
2482 bytestream2_put_byte(&pbc, ts >> 24);
2483 bytestream2_copy_buffer(&pbc, &gbc, size + 3);
2484 bytestream2_skip(&gbc, 4);
2485 bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2486 }
2487 if (bytestream2_tell_p(&pbc) != rt->flv_size) {
2488 av_log(rt, AV_LOG_WARNING, "Incomplete flv packets in "
2489 "RTMP_PT_METADATA packet\n");
2490 rt->flv_size = bytestream2_tell_p(&pbc);
2491 }
2492
2493 return 0;
2494}
2495
2496/**
2497 * Interact with the server by receiving and sending RTMP packets until
2498 * there is some significant data (media data or expected status notification).
2499 *
2500 * @param s reading context
2501 * @param for_header non-zero value tells function to work until it
2502 * gets notification from the server that playing has been started,
2503 * otherwise function will work until some media data is received (or
2504 * an error happens)
2505 * @return 0 for successful operation, negative value in case of error
2506 */
2507static int get_packet(URLContext *s, int for_header)
2508{
2509 RTMPContext *rt = s->priv_data;
2510 int ret;
2511
2512 if (rt->state == STATE_STOPPED)
2513 return AVERROR_EOF;
2514
2515 for (;;) {
2516 RTMPPacket rpkt = { 0 };
2517 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2518 rt->in_chunk_size, &rt->prev_pkt[0],
2519 &rt->nb_prev_pkt[0])) <= 0) {
2520 if (ret == 0) {
2521 return AVERROR(EAGAIN);
2522 } else {
2523 return AVERROR(EIO);
2524 }
2525 }
2526
2527 // Track timestamp for later use
2528 rt->last_timestamp = rpkt.timestamp;
2529
2530 rt->bytes_read += ret;
2531 if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
2532 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2533 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) {
2535 return ret;
2536 }
2537 rt->last_bytes_read = rt->bytes_read;
2538 }
2539
2540 ret = rtmp_parse_result(s, rt, &rpkt);
2541
2542 // At this point we must check if we are in the seek state and continue
2543 // with the next packet. handle_invoke will get us out of this state
2544 // when the right message is encountered
2545 if (rt->state == STATE_SEEKING) {
2547 // We continue, let the natural flow of things happen:
2548 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2549 continue;
2550 }
2551
2552 if (ret < 0) {//serious error in current packet
2554 return ret;
2555 }
2556 if (rt->do_reconnect && for_header) {
2558 return 0;
2559 }
2560 if (rt->state == STATE_STOPPED) {
2562 return AVERROR_EOF;
2563 }
2564 if (for_header && (rt->state == STATE_PLAYING ||
2565 rt->state == STATE_PUBLISHING ||
2566 rt->state == STATE_SENDING ||
2567 rt->state == STATE_RECEIVING)) {
2569 return 0;
2570 }
2571 if (!rpkt.size || !rt->is_input) {
2573 continue;
2574 }
2575 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2576 ret = append_flv_data(rt, &rpkt, 0);
2578 return ret;
2579 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2580 ret = handle_notify(s, &rpkt);
2582 return ret;
2583 } else if (rpkt.type == RTMP_PT_METADATA) {
2584 ret = handle_metadata(rt, &rpkt);
2586 return ret;
2587 }
2589 }
2590}
2591
2593{
2594 RTMPContext *rt = h->priv_data;
2595 int ret = 0, i, j;
2596
2597 if (!rt->is_input) {
2598 rt->flv_data = NULL;
2599 if (rt->out_pkt.size)
2601 if (rt->state > STATE_FCPUBLISH)
2603 }
2604 if (rt->state > STATE_HANDSHAKED)
2605 ret = gen_delete_stream(h, rt);
2606 for (i = 0; i < 2; i++) {
2607 for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2609 av_freep(&rt->prev_pkt[i]);
2610 }
2611
2613 av_freep(&rt->flv_data);
2614 ffurl_closep(&rt->stream);
2615 return ret;
2616}
2617
2618/**
2619 * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2620 * demuxer about the duration of the stream.
2621 *
2622 * This should only be done if there was no real onMetadata packet sent by the
2623 * server at the start of the stream and if we were able to retrieve a valid
2624 * duration via a getStreamLength call.
2625 *
2626 * @return 0 for successful operation, negative value in case of error
2627 */
2629{
2630 // We need to insert the metadata packet directly after the FLV
2631 // header, i.e. we need to move all other already read data by the
2632 // size of our fake metadata packet.
2633
2634 uint8_t* p;
2635 // Keep old flv_data pointer
2636 uint8_t* old_flv_data = rt->flv_data;
2637 // Allocate a new flv_data pointer with enough space for the additional package
2638 if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2639 rt->flv_data = old_flv_data;
2640 return AVERROR(ENOMEM);
2641 }
2642
2643 // Copy FLV header
2644 memcpy(rt->flv_data, old_flv_data, 13);
2645 // Copy remaining packets
2646 memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2647 // Increase the size by the injected packet
2648 rt->flv_size += 55;
2649 // Delete the old FLV data
2650 av_freep(&old_flv_data);
2651
2652 p = rt->flv_data + 13;
2653 bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2654 bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2655 bytestream_put_be24(&p, 0); // timestamp
2656 bytestream_put_be32(&p, 0); // reserved
2657
2658 // first event name as a string
2659 bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2660 // "onMetaData" as AMF string
2661 bytestream_put_be16(&p, 10);
2662 bytestream_put_buffer(&p, "onMetaData", 10);
2663
2664 // mixed array (hash) with size and string/type/data tuples
2665 bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2666 bytestream_put_be32(&p, 1); // metadata_count
2667
2668 // "duration" as AMF string
2669 bytestream_put_be16(&p, 8);
2670 bytestream_put_buffer(&p, "duration", 8);
2671 bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2672 bytestream_put_be64(&p, av_double2int(rt->duration));
2673
2674 // Finalise object
2675 bytestream_put_be16(&p, 0); // Empty string
2676 bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2677 bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2678
2679 return 0;
2680}
2681
2682/**
2683 * Open RTMP connection and verify that the stream can be played.
2684 *
2685 * URL syntax: rtmp://server[:port][/app][/playpath]
2686 * where 'app' is first one or two directories in the path
2687 * (e.g. /ondemand/, /flash/live/, etc.)
2688 * and 'playpath' is a file name (the rest of the path,
2689 * may be prefixed with "mp4:")
2690 */
2691static int rtmp_open(URLContext *s, const char *uri, int flags, AVDictionary **opts)
2692{
2693 RTMPContext *rt = s->priv_data;
2694 char proto[8], hostname[256], path[1024], auth[100], *fname;
2695 char *old_app, *qmark, *n, fname_buffer[1024];
2696 uint8_t buf[2048];
2697 int port;
2698 int ret;
2699
2700 if (rt->listen_timeout > 0)
2701 rt->listen = 1;
2702
2703 rt->is_input = !(flags & AVIO_FLAG_WRITE);
2704
2705 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2706 hostname, sizeof(hostname), &port,
2707 path, sizeof(path), s->filename);
2708
2709 n = strchr(path, ' ');
2710 if (n) {
2712 "Detected librtmp style URL parameters, these aren't supported "
2713 "by the libavformat internal RTMP handler currently enabled. "
2714 "See the documentation for the correct way to pass parameters.\n");
2715 *n = '\0'; // Trim not supported part
2716 }
2717
2718 if (auth[0]) {
2719 char *ptr = strchr(auth, ':');
2720 if (ptr) {
2721 *ptr = '\0';
2722 av_strlcpy(rt->username, auth, sizeof(rt->username));
2723 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2724 }
2725 }
2726
2727 if (rt->listen && strcmp(proto, "rtmp")) {
2728 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2729 proto);
2730 return AVERROR(EINVAL);
2731 }
2732 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2733 if (!strcmp(proto, "rtmpts"))
2734 av_dict_set(opts, "ffrtmphttp_tls", "1", AV_DICT_MATCH_CASE);
2735
2736 /* open the http tunneling connection */
2737 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2738 } else if (!strcmp(proto, "rtmps")) {
2739 /* open the tls connection */
2740 if (port < 0)
2741 port = RTMPS_DEFAULT_PORT;
2742 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2743 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2744 if (!strcmp(proto, "rtmpte"))
2745 av_dict_set(opts, "ffrtmpcrypt_tunneling", "1", 1);
2746
2747 /* open the encrypted connection */
2748 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2749 rt->encrypted = 1;
2750 } else {
2751 /* open the tcp connection */
2752 if (port < 0)
2753 port = RTMP_DEFAULT_PORT;
2754 if (rt->listen)
2755 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2756 "?listen&listen_timeout=%d&tcp_nodelay=%d",
2757 rt->listen_timeout < 0 ? -1 : rt->listen_timeout * 1000,
2758 rt->tcp_nodelay);
2759 else
2760 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, "?tcp_nodelay=%d", rt->tcp_nodelay);
2761 }
2762
2763reconnect:
2765 &s->interrupt_callback, opts,
2766 s->protocol_whitelist, s->protocol_blacklist, s)) < 0) {
2767 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2768 goto fail;
2769 }
2770
2771 if (rt->swfverify) {
2772 if ((ret = rtmp_calc_swfhash(s)) < 0)
2773 goto fail;
2774 }
2775
2776 rt->state = STATE_START;
2777 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2778 goto fail;
2779 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2780 goto fail;
2781
2782 rt->out_chunk_size = 128;
2783 rt->in_chunk_size = 128; // Probably overwritten later
2784 rt->state = STATE_HANDSHAKED;
2785
2786 // Keep the application name when it has been defined by the user.
2787 old_app = rt->app;
2788
2790 if (!rt->app) {
2791 ret = AVERROR(ENOMEM);
2792 goto fail;
2793 }
2794
2795 //extract "app" part from path
2796 qmark = strchr(path, '?');
2797 if (qmark && strstr(qmark, "slist=")) {
2798 char* amp;
2799 // After slist we have the playpath, the full path is used as app
2800 av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2801 fname = strstr(path, "slist=") + 6;
2802 // Strip any further query parameters from fname
2803 amp = strchr(fname, '&');
2804 if (amp) {
2805 av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2806 sizeof(fname_buffer)));
2807 fname = fname_buffer;
2808 }
2809 } else if (!strncmp(path, "/ondemand/", 10)) {
2810 fname = path + 10;
2811 memcpy(rt->app, "ondemand", 9);
2812 } else {
2813 char *next = *path ? path + 1 : path;
2814 char *p = strchr(next, '/');
2815 if (!p) {
2816 if (old_app) {
2817 // If name of application has been defined by the user, assume that
2818 // playpath is provided in the URL
2819 fname = next;
2820 } else {
2821 fname = NULL;
2822 av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2823 }
2824 } else {
2825 // make sure we do not mismatch a playpath for an application instance
2826 char *c = strchr(p + 1, ':');
2827 fname = strchr(p + 1, '/');
2828 if (!fname || (c && c < fname)) {
2829 fname = p + 1;
2830 av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2831 } else {
2832 fname++;
2833 av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2834 }
2835 }
2836 }
2837
2838 if (old_app) {
2839 // The name of application has been defined by the user, override it.
2840 if (strlen(old_app) >= APP_MAX_LENGTH) {
2841 ret = AVERROR(EINVAL);
2842 goto fail;
2843 }
2844 av_free(rt->app);
2845 rt->app = old_app;
2846 }
2847
2848 if (!rt->playpath) {
2849 int max_len = 1;
2850 if (fname)
2851 max_len = strlen(fname) + 5; // add prefix "mp4:"
2852 rt->playpath = av_malloc(max_len);
2853 if (!rt->playpath) {
2854 ret = AVERROR(ENOMEM);
2855 goto fail;
2856 }
2857
2858 if (fname) {
2859 int len = strlen(fname);
2860 if (!strchr(fname, ':') && len >= 4 &&
2861 (!strcmp(fname + len - 4, ".f4v") ||
2862 !strcmp(fname + len - 4, ".mp4"))) {
2863 memcpy(rt->playpath, "mp4:", 5);
2864 } else {
2865 if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2866 fname[len - 4] = '\0';
2867 rt->playpath[0] = 0;
2868 }
2869 av_strlcat(rt->playpath, fname, max_len);
2870 } else {
2871 rt->playpath[0] = '\0';
2872 }
2873 }
2874
2875 if (!rt->tcurl) {
2877 if (!rt->tcurl) {
2878 ret = AVERROR(ENOMEM);
2879 goto fail;
2880 }
2881 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2882 port, "/%s", rt->app);
2883 }
2884
2885 if (!rt->flashver) {
2887 if (!rt->flashver) {
2888 ret = AVERROR(ENOMEM);
2889 goto fail;
2890 }
2891 if (rt->is_input) {
2892 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2895 } else {
2896 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2897 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2898 }
2899 }
2900 if ( strlen(rt->flashver) > FLASHVER_MAX_LENGTH
2901 || strlen(rt->tcurl ) > TCURL_MAX_LENGTH
2902 ) {
2903 ret = AVERROR(EINVAL);
2904 goto fail;
2905 }
2906
2907 rt->receive_report_size = 1048576;
2908 rt->bytes_read = 0;
2909 rt->has_audio = 0;
2910 rt->has_video = 0;
2911 rt->received_metadata = 0;
2912 rt->last_bytes_read = 0;
2913 rt->max_sent_unacked = 2500000;
2914 rt->duration = 0;
2915
2916 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2917 proto, path, rt->app, rt->playpath);
2918 if (!rt->listen) {
2919 if ((ret = gen_connect(s, rt)) < 0)
2920 goto fail;
2921 } else {
2922 if ((ret = read_connect(s, s->priv_data)) < 0)
2923 goto fail;
2924 }
2925
2926 do {
2927 ret = get_packet(s, 1);
2928 } while (ret == AVERROR(EAGAIN));
2929 if (ret < 0)
2930 goto fail;
2931
2932 if (rt->do_reconnect) {
2933 int i;
2934 ffurl_closep(&rt->stream);
2935 rt->do_reconnect = 0;
2936 rt->nb_invokes = 0;
2937 for (i = 0; i < 2; i++)
2938 memset(rt->prev_pkt[i], 0,
2939 sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2941 goto reconnect;
2942 }
2943
2944 if (rt->is_input) {
2945 // generate FLV header for demuxer
2946 rt->flv_size = 13;
2947 if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2948 goto fail;
2949 rt->flv_off = 0;
2950 memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2951
2952 // Read packets until we reach the first A/V packet or read metadata.
2953 // If there was a metadata package in front of the A/V packets, we can
2954 // build the FLV header from this. If we do not receive any metadata,
2955 // the FLV decoder will allocate the needed streams when their first
2956 // audio or video packet arrives.
2957 while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2958 if ((ret = get_packet(s, 0)) < 0)
2959 goto fail;
2960 }
2961
2962 // Either after we have read the metadata or (if there is none) the
2963 // first packet of an A/V stream, we have a better knowledge about the
2964 // streams, so set the FLV header accordingly.
2965 if (rt->has_audio) {
2967 }
2968 if (rt->has_video) {
2970 }
2971
2972 // If we received the first packet of an A/V stream and no metadata but
2973 // the server returned a valid duration, create a fake metadata packet
2974 // to inform the FLV decoder about the duration.
2975 if (!rt->received_metadata && rt->duration > 0) {
2976 if ((ret = inject_fake_duration_metadata(rt)) < 0)
2977 goto fail;
2978 }
2979 } else {
2980 rt->flv_size = 0;
2981 rt->flv_data = NULL;
2982 rt->flv_off = 0;
2983 rt->skip_bytes = 13;
2984 }
2985
2986 s->max_packet_size = rt->stream->max_packet_size;
2987 s->is_streamed = 1;
2988 return 0;
2989
2990fail:
2991 rtmp_close(s);
2992 return ret;
2993}
2994
2995static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2996{
2997 RTMPContext *rt = s->priv_data;
2998 int orig_size = size;
2999 int ret;
3000
3001 while (size > 0) {
3002 int data_left = rt->flv_size - rt->flv_off;
3003
3004 if (data_left >= size) {
3005 memcpy(buf, rt->flv_data + rt->flv_off, size);
3006 rt->flv_off += size;
3007 return orig_size;
3008 }
3009 if (data_left > 0) {
3010 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
3011 buf += data_left;
3012 size -= data_left;
3013 rt->flv_off = rt->flv_size;
3014 return data_left;
3015 }
3016 if ((ret = get_packet(s, 0)) < 0)
3017 return ret;
3018 }
3019 return orig_size;
3020}
3021
3022static int64_t rtmp_seek(void *opaque, int stream_index, int64_t timestamp,
3023 int flags)
3024{
3025 URLContext *s = opaque;
3026 RTMPContext *rt = s->priv_data;
3027 int ret;
3029 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
3030 stream_index, timestamp, flags);
3031 if ((ret = gen_seek(s, rt, timestamp)) < 0) {
3033 "Unable to send seek command on stream index %d at timestamp "
3034 "%"PRId64" with flags %08x\n",
3035 stream_index, timestamp, flags);
3036 return ret;
3037 }
3038 rt->flv_off = rt->flv_size;
3039 rt->state = STATE_SEEKING;
3040 return timestamp;
3041}
3042
3043static int rtmp_pause(void *opaque, int pause)
3044{
3045 URLContext *s = opaque;
3046 RTMPContext *rt = s->priv_data;
3047 int ret;
3048 av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
3049 rt->last_timestamp);
3050 if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
3051 av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
3052 rt->last_timestamp);
3053 return ret;
3054 }
3055 return 0;
3056}
3057
3058static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
3059{
3060 RTMPContext *rt = s->priv_data;
3061 int size_temp = size;
3062 int pktsize, pkttype, copy;
3063 uint32_t ts;
3064 const uint8_t *buf_temp = buf;
3065 uint8_t c;
3066 int ret;
3067
3068 do {
3069 if (rt->skip_bytes) {
3070 int skip = FFMIN(rt->skip_bytes, size_temp);
3071 buf_temp += skip;
3072 size_temp -= skip;
3073 rt->skip_bytes -= skip;
3074 continue;
3075 }
3076
3077 if (rt->flv_header_bytes < RTMP_HEADER) {
3078 const uint8_t *header = rt->flv_header;
3080
3081 copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
3083 rt->flv_header_bytes += copy;
3084 size_temp -= copy;
3085 if (rt->flv_header_bytes < RTMP_HEADER)
3086 break;
3087
3088 pkttype = bytestream_get_byte(&header);
3089 pktsize = bytestream_get_be24(&header);
3090 ts = bytestream_get_be24(&header);
3091 ts |= bytestream_get_byte(&header) << 24;
3092 bytestream_get_be24(&header);
3093 rt->flv_size = pktsize;
3094
3095 if (pkttype == RTMP_PT_VIDEO)
3097
3098 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
3099 pkttype == RTMP_PT_NOTIFY) {
3100 if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
3101 &rt->nb_prev_pkt[1],
3102 channel)) < 0)
3103 return ret;
3104 // Force sending a full 12 bytes header by clearing the
3105 // channel id, to make it not match a potential earlier
3106 // packet in the same channel.
3107 rt->prev_pkt[1][channel].channel_id = 0;
3108 }
3109
3110 //this can be a big packet, it's better to send it right here
3112 pkttype, ts, pktsize)) < 0)
3113 return ret;
3114
3115 // If rt->listen, then we're running as a a server and should
3116 // use the ID that we've sent in Stream Begin and in the
3117 // _result to createStream.
3118 // Otherwise, we're running as a client and should use the ID
3119 // that we've received in the createStream from the server.
3120 rt->out_pkt.extra = (rt->listen) ? rt->nb_streamid : rt->stream_id;
3121 rt->flv_data = rt->out_pkt.data;
3122 }
3123
3124 copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
3125 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
3126 rt->flv_off += copy;
3127 size_temp -= copy;
3128
3129 if (rt->flv_off == rt->flv_size) {
3130 rt->skip_bytes = 4;
3131
3132 if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3133 // For onMetaData and |RtmpSampleAccess packets, we want
3134 // @setDataFrame prepended to the packet before it gets sent.
3135 // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3136 // and onCuePoint).
3137 uint8_t commandbuffer[64];
3138 int stringlen = 0;
3139 GetByteContext gbc;
3140
3141 bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3142 if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3143 &stringlen)) {
3144 if (!strcmp(commandbuffer, "onMetaData") ||
3145 !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3146 uint8_t *ptr;
3147 if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3148 rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3149 return ret;
3150 }
3151 memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3152 rt->out_pkt.size += 16;
3153 ptr = rt->out_pkt.data;
3154 ff_amf_write_string(&ptr, "@setDataFrame");
3155 }
3156 }
3157 }
3158
3159 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3160 return ret;
3161 rt->flv_size = 0;
3162 rt->flv_off = 0;
3163 rt->flv_header_bytes = 0;
3164 rt->flv_nb_packets++;
3165 }
3166 } while (buf_temp - buf < size);
3167
3168 if (rt->flv_nb_packets < rt->flush_interval)
3169 return size;
3170 rt->flv_nb_packets = 0;
3171
3172 /* set stream into nonblocking mode */
3174
3175 /* try to read one byte from the stream */
3176 ret = ffurl_read(rt->stream, &c, 1);
3177
3178 /* switch the stream back into blocking mode */
3180
3181 if (ret == AVERROR(EAGAIN)) {
3182 /* no incoming data to handle */
3183 return size;
3184 } else if (ret < 0) {
3185 return ret;
3186 } else if (ret == 1) {
3187 RTMPPacket rpkt = { 0 };
3188
3189 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3190 rt->in_chunk_size,
3191 &rt->prev_pkt[0],
3192 &rt->nb_prev_pkt[0], c)) <= 0)
3193 return ret;
3194
3195 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3196 return ret;
3197
3199 }
3200
3201 return size;
3202}
3203
3204#define OFFSET(x) offsetof(RTMPContext, x)
3205#define DEC AV_OPT_FLAG_DECODING_PARAM
3206#define ENC AV_OPT_FLAG_ENCODING_PARAM
3207
3208static const AVOption rtmp_options[] = {
3209 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3210 {"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},
3211 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3212 {"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},
3213 {"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},
3214 {"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},
3215 {"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"},
3216 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, .unit = "rtmp_live"},
3217 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, .unit = "rtmp_live"},
3218 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, .unit = "rtmp_live"},
3219 {"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},
3220 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3221 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3222 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3223 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3224 {"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},
3225 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3226 {"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},
3227 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_listen" },
3228 {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, .unit = "rtmp_listen" },
3229 {"tcp_nodelay", "Use TCP_NODELAY to disable Nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC|ENC},
3230 {"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" },
3231 { NULL },
3232};
3233
3234#define RTMP_PROTOCOL_0(flavor)
3235#define RTMP_PROTOCOL_1(flavor) \
3236static const AVClass flavor##_class = { \
3237 .class_name = #flavor, \
3238 .item_name = av_default_item_name, \
3239 .option = rtmp_options, \
3240 .version = LIBAVUTIL_VERSION_INT, \
3241}; \
3242 \
3243const URLProtocol ff_##flavor##_protocol = { \
3244 .name = #flavor, \
3245 .url_open2 = rtmp_open, \
3246 .url_read = rtmp_read, \
3247 .url_read_seek = rtmp_seek, \
3248 .url_read_pause = rtmp_pause, \
3249 .url_write = rtmp_write, \
3250 .url_close = rtmp_close, \
3251 .priv_data_size = sizeof(RTMPContext), \
3252 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3253 .priv_data_class= &flavor##_class, \
3254};
3255#define RTMP_PROTOCOL_2(flavor, enabled) \
3256 RTMP_PROTOCOL_ ## enabled(flavor)
3257#define RTMP_PROTOCOL_3(flavor, config) \
3258 RTMP_PROTOCOL_2(flavor, config)
3259#define RTMP_PROTOCOL(flavor, uppercase) \
3260 RTMP_PROTOCOL_3(flavor, CONFIG_ ## uppercase ## _PROTOCOL)
3261
3262RTMP_PROTOCOL(rtmp, RTMP)
3263RTMP_PROTOCOL(rtmpe, RTMPE)
3264RTMP_PROTOCOL(rtmps, RTMPS)
3265RTMP_PROTOCOL(rtmpt, RTMPT)
3266RTMP_PROTOCOL(rtmpte, RTMPTE)
3267RTMP_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:466
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition avio.c:663
int ffurl_close(URLContext *h)
Definition avio.c:686
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:632
#define AVIO_FLAG_READ
read-only
Definition avio.h:630
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition avio.h:481
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:631
#define AVIO_FLAG_READ_WRITE
read-write pseudo flag
Definition avio.h:632
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition avio.h:649
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:139
#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
char * path
Definition ffplay.c:385
int ret
Definition ffplay.c:391
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:152
#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:87
#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:289
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:326
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:957
int index
Definition gxfenc.c:90
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
enum MPFType type
Definition jpegmpfenc.c:55
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:473
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:503
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:571
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:418
void ff_rtmp_packet_destroy(RTMPPacket *pkt)
Free RTMP packet.
Definition rtmppkt.c:436
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:710
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:2336
static const AVOption rtmp_options[]
Definition rtmpproto.c:3208
static int rtmp_read(URLContext *s, uint8_t *buf, int size)
Definition rtmpproto.c:2995
static int read_number_result(RTMPPacket *pkt, double *number)
Read the AMF_NUMBER response ("_result") to a function call (e.g.
Definition rtmpproto.c:2105
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:1987
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:1878
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:2592
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:2628
static int write_begin(URLContext *s)
Definition rtmpproto.c:1917
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:2244
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:3043
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:2299
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:1783
static int64_t rtmp_seek(void *opaque, int stream_index, int64_t timestamp, int flags)
Definition rtmpproto.c:3022
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:2399
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:2135
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:2507
#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:1943
static int update_offset(RTMPContext *rt, int size)
Definition rtmpproto.c:2275
#define OFFSET(x)
Definition rtmpproto.c:3204
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:2691
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:2207
static int handle_metadata(RTMPContext *rt, RTMPPacket *pkt)
Definition rtmpproto.c:2444
#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:3058
static int handle_user_control(URLContext *s, RTMPPacket *pkt)
Definition rtmpproto.c:1608
#define RTMP_PROTOCOL(flavor, uppercase)
Definition rtmpproto.c:3259
static const uint8_t header[24]
Definition sdr2.c:68
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:33
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:225
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:205
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:184
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]