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