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