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