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