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