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