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