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