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