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