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