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