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