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_whitelist(&stream, rt->swfverify, AVIO_FLAG_READ,
1122  &s->interrupt_callback, NULL,
1123  s->protocol_whitelist)) < 0) {
1124  av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1125  goto fail;
1126  }
1127 
1128  if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1129  ret = AVERROR(EIO);
1130  goto fail;
1131  }
1132 
1133  if (!(in_data = av_malloc(in_size))) {
1134  ret = AVERROR(ENOMEM);
1135  goto fail;
1136  }
1137 
1138  if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1139  goto fail;
1140 
1141  if (in_size < 3) {
1142  ret = AVERROR_INVALIDDATA;
1143  goto fail;
1144  }
1145 
1146  if (!memcmp(in_data, "CWS", 3)) {
1147  /* Decompress the SWF player file using Zlib. */
1148  if (!(out_data = av_malloc(8))) {
1149  ret = AVERROR(ENOMEM);
1150  goto fail;
1151  }
1152  *in_data = 'F'; // magic stuff
1153  memcpy(out_data, in_data, 8);
1154  out_size = 8;
1155 
1156 #if CONFIG_ZLIB
1157  if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1158  &out_data, &out_size)) < 0)
1159  goto fail;
1160 #else
1161  av_log(s, AV_LOG_ERROR,
1162  "Zlib is required for decompressing the SWF player file.\n");
1163  ret = AVERROR(EINVAL);
1164  goto fail;
1165 #endif
1166  swfsize = out_size;
1167  swfdata = out_data;
1168  } else {
1169  swfsize = in_size;
1170  swfdata = in_data;
1171  }
1172 
1173  /* Compute the SHA256 hash of the SWF player file. */
1174  if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1175  "Genuine Adobe Flash Player 001", 30,
1176  swfhash)) < 0)
1177  goto fail;
1178 
1179  /* Set SWFVerification parameters. */
1180  av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1181  rt->swfsize = swfsize;
1182 
1183 fail:
1184  av_freep(&in_data);
1185  av_freep(&out_data);
1186  ffurl_close(stream);
1187  return ret;
1188 }
1189 
1190 /**
1191  * Perform handshake with the server by means of exchanging pseudorandom data
1192  * signed with HMAC-SHA2 digest.
1193  *
1194  * @return 0 if handshake succeeds, negative value otherwise
1195  */
1197 {
1198  AVLFG rnd;
1199  uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1200  3, // unencrypted data
1201  0, 0, 0, 0, // client uptime
1206  };
1207  uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1208  uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1209  int i;
1210  int server_pos, client_pos;
1211  uint8_t digest[32], signature[32];
1212  int ret, type = 0;
1213 
1214  av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
1215 
1216  av_lfg_init(&rnd, 0xDEADC0DE);
1217  // generate handshake packet - 1536 bytes of pseudorandom data
1218  for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1219  tosend[i] = av_lfg_get(&rnd) >> 24;
1220 
1221  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1222  /* When the client wants to use RTMPE, we have to change the command
1223  * byte to 0x06 which means to use encrypted data and we have to set
1224  * the flash version to at least 9.0.115.0. */
1225  tosend[0] = 6;
1226  tosend[5] = 128;
1227  tosend[6] = 0;
1228  tosend[7] = 3;
1229  tosend[8] = 2;
1230 
1231  /* Initialize the Diffie-Hellmann context and generate the public key
1232  * to send to the server. */
1233  if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1234  return ret;
1235  }
1236 
1237  client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
1238  if (client_pos < 0)
1239  return client_pos;
1240 
1241  if ((ret = ffurl_write(rt->stream, tosend,
1242  RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1243  av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1244  return ret;
1245  }
1246 
1247  if ((ret = ffurl_read_complete(rt->stream, serverdata,
1248  RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1249  av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1250  return ret;
1251  }
1252 
1253  if ((ret = ffurl_read_complete(rt->stream, clientdata,
1255  av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
1256  return ret;
1257  }
1258 
1259  av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
1260  av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
1261  serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1262 
1263  if (rt->is_input && serverdata[5] >= 3) {
1264  server_pos = rtmp_validate_digest(serverdata + 1, 772);
1265  if (server_pos < 0)
1266  return server_pos;
1267 
1268  if (!server_pos) {
1269  type = 1;
1270  server_pos = rtmp_validate_digest(serverdata + 1, 8);
1271  if (server_pos < 0)
1272  return server_pos;
1273 
1274  if (!server_pos) {
1275  av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
1276  return AVERROR(EIO);
1277  }
1278  }
1279 
1280  /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1281  * key are the last 32 bytes of the server handshake. */
1282  if (rt->swfsize) {
1283  if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1284  RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1285  return ret;
1286  }
1287 
1288  ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1290  digest);
1291  if (ret < 0)
1292  return ret;
1293 
1294  ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
1295  0, digest, 32, signature);
1296  if (ret < 0)
1297  return ret;
1298 
1299  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1300  /* Compute the shared secret key sent by the server and initialize
1301  * the RC4 encryption. */
1302  if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1303  tosend + 1, type)) < 0)
1304  return ret;
1305 
1306  /* Encrypt the signature received by the server. */
1307  ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1308  }
1309 
1310  if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
1311  av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
1312  return AVERROR(EIO);
1313  }
1314 
1315  for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1316  tosend[i] = av_lfg_get(&rnd) >> 24;
1317  ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1319  digest);
1320  if (ret < 0)
1321  return ret;
1322 
1323  ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1324  digest, 32,
1325  tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1326  if (ret < 0)
1327  return ret;
1328 
1329  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1330  /* Encrypt the signature to be send to the server. */
1331  ff_rtmpe_encrypt_sig(rt->stream, tosend +
1332  RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1333  serverdata[0]);
1334  }
1335 
1336  // write reply back to the server
1337  if ((ret = ffurl_write(rt->stream, tosend,
1338  RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1339  return ret;
1340 
1341  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1342  /* Set RC4 keys for encryption and update the keystreams. */
1343  if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1344  return ret;
1345  }
1346  } else {
1347  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1348  /* Compute the shared secret key sent by the server and initialize
1349  * the RC4 encryption. */
1350  if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1351  tosend + 1, 1)) < 0)
1352  return ret;
1353 
1354  if (serverdata[0] == 9) {
1355  /* Encrypt the signature received by the server. */
1356  ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1357  serverdata[0]);
1358  }
1359  }
1360 
1361  if ((ret = ffurl_write(rt->stream, serverdata + 1,
1363  return ret;
1364 
1365  if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->encrypted) {
1366  /* Set RC4 keys for encryption and update the keystreams. */
1367  if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1368  return ret;
1369  }
1370  }
1371 
1372  return 0;
1373 }
1374 
1375 static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1376  uint32_t *second_int, char *arraydata,
1377  int size)
1378 {
1379  int inoutsize;
1380 
1381  inoutsize = ffurl_read_complete(rt->stream, arraydata,
1383  if (inoutsize <= 0)
1384  return AVERROR(EIO);
1385  if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1386  av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1387  " not following standard\n", (int)inoutsize);
1388  return AVERROR(EINVAL);
1389  }
1390 
1391  *first_int = AV_RB32(arraydata);
1392  *second_int = AV_RB32(arraydata + 4);
1393  return 0;
1394 }
1395 
1396 static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1397  uint32_t second_int, char *arraydata, int size)
1398 {
1399  int inoutsize;
1400 
1401  AV_WB32(arraydata, first_int);
1402  AV_WB32(arraydata + 4, second_int);
1403  inoutsize = ffurl_write(rt->stream, arraydata,
1405  if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1406  av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1407  return AVERROR(EIO);
1408  }
1409 
1410  return 0;
1411 }
1412 
1413 /**
1414  * rtmp handshake server side
1415  */
1417 {
1419  uint32_t hs_epoch;
1420  uint32_t hs_my_epoch;
1423  uint32_t zeroes;
1424  uint32_t temp = 0;
1425  int randomidx = 0;
1426  int inoutsize = 0;
1427  int ret;
1428 
1429  inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1430  if (inoutsize <= 0) {
1431  av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1432  return AVERROR(EIO);
1433  }
1434  // Check Version
1435  if (buffer[0] != 3) {
1436  av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1437  return AVERROR(EIO);
1438  }
1439  if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1440  av_log(s, AV_LOG_ERROR,
1441  "Unable to write answer - RTMP S0\n");
1442  return AVERROR(EIO);
1443  }
1444  /* Receive C1 */
1445  ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1447  if (ret) {
1448  av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1449  return ret;
1450  }
1451  /* Send S1 */
1452  /* By now same epoch will be sent */
1453  hs_my_epoch = hs_epoch;
1454  /* Generate random */
1455  for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
1456  randomidx += 4)
1457  AV_WB32(hs_s1 + randomidx, av_get_random_seed());
1458 
1459  ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1461  if (ret) {
1462  av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1463  return ret;
1464  }
1465  /* Send S2 */
1466  ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1468  if (ret) {
1469  av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1470  return ret;
1471  }
1472  /* Receive C2 */
1473  ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1475  if (ret) {
1476  av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1477  return ret;
1478  }
1479  if (temp != hs_my_epoch)
1481  "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1482  if (memcmp(buffer + 8, hs_s1 + 8,
1485  "Erroneous C2 Message random does not match up\n");
1486 
1487  return 0;
1488 }
1489 
1491 {
1492  RTMPContext *rt = s->priv_data;
1493  int ret;
1494 
1495  if (pkt->size < 4) {
1496  av_log(s, AV_LOG_ERROR,
1497  "Too short chunk size change packet (%d)\n",
1498  pkt->size);
1499  return AVERROR_INVALIDDATA;
1500  }
1501 
1502  if (!rt->is_input) {
1503  /* Send the same chunk size change packet back to the server,
1504  * setting the outgoing chunk size to the same as the incoming one. */
1505  if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
1506  &rt->prev_pkt[1], &rt->nb_prev_pkt[1])) < 0)
1507  return ret;
1508  rt->out_chunk_size = AV_RB32(pkt->data);
1509  }
1510 
1511  rt->in_chunk_size = AV_RB32(pkt->data);
1512  if (rt->in_chunk_size <= 0) {
1513  av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1514  rt->in_chunk_size);
1515  return AVERROR_INVALIDDATA;
1516  }
1517  av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1518  rt->in_chunk_size);
1519 
1520  return 0;
1521 }
1522 
1524 {
1525  RTMPContext *rt = s->priv_data;
1526  int t, ret;
1527 
1528  if (pkt->size < 2) {
1529  av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1530  pkt->size);
1531  return AVERROR_INVALIDDATA;
1532  }
1533 
1534  t = AV_RB16(pkt->data);
1535  if (t == 6) {
1536  if ((ret = gen_pong(s, rt, pkt)) < 0)
1537  return ret;
1538  } else if (t == 26) {
1539  if (rt->swfsize) {
1540  if ((ret = gen_swf_verification(s, rt)) < 0)
1541  return ret;
1542  } else {
1543  av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1544  }
1545  }
1546 
1547  return 0;
1548 }
1549 
1551 {
1552  RTMPContext *rt = s->priv_data;
1553 
1554  if (pkt->size < 4) {
1555  av_log(s, AV_LOG_ERROR,
1556  "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1557  pkt->size);
1558  return AVERROR_INVALIDDATA;
1559  }
1560 
1561  rt->client_report_size = AV_RB32(pkt->data);
1562  if (rt->client_report_size <= 0) {
1563  av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1564  rt->client_report_size);
1565  return AVERROR_INVALIDDATA;
1566 
1567  }
1568  av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1569  rt->client_report_size >>= 1;
1570 
1571  return 0;
1572 }
1573 
1575 {
1576  RTMPContext *rt = s->priv_data;
1577 
1578  if (pkt->size < 4) {
1579  av_log(s, AV_LOG_ERROR,
1580  "Too short server bandwidth report packet (%d)\n",
1581  pkt->size);
1582  return AVERROR_INVALIDDATA;
1583  }
1584 
1585  rt->server_bw = AV_RB32(pkt->data);
1586  if (rt->server_bw <= 0) {
1587  av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1588  rt->server_bw);
1589  return AVERROR_INVALIDDATA;
1590  }
1591  av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1592 
1593  return 0;
1594 }
1595 
1596 static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1597  const char *opaque, const char *challenge)
1598 {
1599  uint8_t hash[16];
1600  char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1601  struct AVMD5 *md5 = av_md5_alloc();
1602  if (!md5)
1603  return AVERROR(ENOMEM);
1604 
1605  snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1606 
1607  av_md5_init(md5);
1608  av_md5_update(md5, user, strlen(user));
1609  av_md5_update(md5, salt, strlen(salt));
1610  av_md5_update(md5, rt->password, strlen(rt->password));
1611  av_md5_final(md5, hash);
1612  av_base64_encode(hashstr, sizeof(hashstr), hash,
1613  sizeof(hash));
1614  av_md5_init(md5);
1615  av_md5_update(md5, hashstr, strlen(hashstr));
1616  if (opaque)
1617  av_md5_update(md5, opaque, strlen(opaque));
1618  else if (challenge)
1619  av_md5_update(md5, challenge, strlen(challenge));
1620  av_md5_update(md5, challenge2, strlen(challenge2));
1621  av_md5_final(md5, hash);
1622  av_base64_encode(hashstr, sizeof(hashstr), hash,
1623  sizeof(hash));
1624  snprintf(rt->auth_params, sizeof(rt->auth_params),
1625  "?authmod=%s&user=%s&challenge=%s&response=%s",
1626  "adobe", user, challenge2, hashstr);
1627  if (opaque)
1628  av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1629  "&opaque=%s", opaque);
1630 
1631  av_free(md5);
1632  return 0;
1633 }
1634 
1635 static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
1636 {
1637  uint8_t hash[16];
1638  char hashstr1[33], hashstr2[33];
1639  const char *realm = "live";
1640  const char *method = "publish";
1641  const char *qop = "auth";
1642  const char *nc = "00000001";
1643  char cnonce[10];
1644  struct AVMD5 *md5 = av_md5_alloc();
1645  if (!md5)
1646  return AVERROR(ENOMEM);
1647 
1648  snprintf(cnonce, sizeof(cnonce), "%08x", av_get_random_seed());
1649 
1650  av_md5_init(md5);
1651  av_md5_update(md5, user, strlen(user));
1652  av_md5_update(md5, ":", 1);
1653  av_md5_update(md5, realm, strlen(realm));
1654  av_md5_update(md5, ":", 1);
1655  av_md5_update(md5, rt->password, strlen(rt->password));
1656  av_md5_final(md5, hash);
1657  ff_data_to_hex(hashstr1, hash, 16, 1);
1658  hashstr1[32] = '\0';
1659 
1660  av_md5_init(md5);
1661  av_md5_update(md5, method, strlen(method));
1662  av_md5_update(md5, ":/", 2);
1663  av_md5_update(md5, rt->app, strlen(rt->app));
1664  if (!strchr(rt->app, '/'))
1665  av_md5_update(md5, "/_definst_", strlen("/_definst_"));
1666  av_md5_final(md5, hash);
1667  ff_data_to_hex(hashstr2, hash, 16, 1);
1668  hashstr2[32] = '\0';
1669 
1670  av_md5_init(md5);
1671  av_md5_update(md5, hashstr1, strlen(hashstr1));
1672  av_md5_update(md5, ":", 1);
1673  if (nonce)
1674  av_md5_update(md5, nonce, strlen(nonce));
1675  av_md5_update(md5, ":", 1);
1676  av_md5_update(md5, nc, strlen(nc));
1677  av_md5_update(md5, ":", 1);
1678  av_md5_update(md5, cnonce, strlen(cnonce));
1679  av_md5_update(md5, ":", 1);
1680  av_md5_update(md5, qop, strlen(qop));
1681  av_md5_update(md5, ":", 1);
1682  av_md5_update(md5, hashstr2, strlen(hashstr2));
1683  av_md5_final(md5, hash);
1684  ff_data_to_hex(hashstr1, hash, 16, 1);
1685 
1686  snprintf(rt->auth_params, sizeof(rt->auth_params),
1687  "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1688  "llnw", user, nonce, cnonce, nc, hashstr1);
1689 
1690  av_free(md5);
1691  return 0;
1692 }
1693 
1694 static int handle_connect_error(URLContext *s, const char *desc)
1695 {
1696  RTMPContext *rt = s->priv_data;
1697  char buf[300], *ptr, authmod[15];
1698  int i = 0, ret = 0;
1699  const char *user = "", *salt = "", *opaque = NULL,
1700  *challenge = NULL, *cptr = NULL, *nonce = NULL;
1701 
1702  if (!(cptr = strstr(desc, "authmod=adobe")) &&
1703  !(cptr = strstr(desc, "authmod=llnw"))) {
1704  av_log(s, AV_LOG_ERROR,
1705  "Unknown connect error (unsupported authentication method?)\n");
1706  return AVERROR_UNKNOWN;
1707  }
1708  cptr += strlen("authmod=");
1709  while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1710  authmod[i++] = *cptr++;
1711  authmod[i] = '\0';
1712 
1713  if (!rt->username[0] || !rt->password[0]) {
1714  av_log(s, AV_LOG_ERROR, "No credentials set\n");
1715  return AVERROR_UNKNOWN;
1716  }
1717 
1718  if (strstr(desc, "?reason=authfailed")) {
1719  av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1720  return AVERROR_UNKNOWN;
1721  } else if (strstr(desc, "?reason=nosuchuser")) {
1722  av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1723  return AVERROR_UNKNOWN;
1724  }
1725 
1726  if (rt->auth_tried) {
1727  av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1728  return AVERROR_UNKNOWN;
1729  }
1730 
1731  rt->auth_params[0] = '\0';
1732 
1733  if (strstr(desc, "code=403 need auth")) {
1734  snprintf(rt->auth_params, sizeof(rt->auth_params),
1735  "?authmod=%s&user=%s", authmod, rt->username);
1736  return 0;
1737  }
1738 
1739  if (!(cptr = strstr(desc, "?reason=needauth"))) {
1740  av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1741  return AVERROR_UNKNOWN;
1742  }
1743 
1744  av_strlcpy(buf, cptr + 1, sizeof(buf));
1745  ptr = buf;
1746 
1747  while (ptr) {
1748  char *next = strchr(ptr, '&');
1749  char *value = strchr(ptr, '=');
1750  if (next)
1751  *next++ = '\0';
1752  if (value) {
1753  *value++ = '\0';
1754  if (!strcmp(ptr, "user")) {
1755  user = value;
1756  } else if (!strcmp(ptr, "salt")) {
1757  salt = value;
1758  } else if (!strcmp(ptr, "opaque")) {
1759  opaque = value;
1760  } else if (!strcmp(ptr, "challenge")) {
1761  challenge = value;
1762  } else if (!strcmp(ptr, "nonce")) {
1763  nonce = value;
1764  } else {
1765  av_log(s, AV_LOG_INFO, "Ignoring unsupported var %s\n", ptr);
1766  }
1767  } else {
1768  av_log(s, AV_LOG_WARNING, "Variable %s has NULL value\n", ptr);
1769  }
1770  ptr = next;
1771  }
1772 
1773  if (!strcmp(authmod, "adobe")) {
1774  if ((ret = do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1775  return ret;
1776  } else {
1777  if ((ret = do_llnw_auth(rt, user, nonce)) < 0)
1778  return ret;
1779  }
1780 
1781  rt->auth_tried = 1;
1782  return 0;
1783 }
1784 
1786 {
1787  RTMPContext *rt = s->priv_data;
1788  const uint8_t *data_end = pkt->data + pkt->size;
1789  char *tracked_method = NULL;
1790  int level = AV_LOG_ERROR;
1791  uint8_t tmpstr[256];
1792  int ret;
1793 
1794  if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1795  return ret;
1796 
1797  if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1798  "description", tmpstr, sizeof(tmpstr))) {
1799  if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1800  !strcmp(tracked_method, "releaseStream") ||
1801  !strcmp(tracked_method, "FCSubscribe") ||
1802  !strcmp(tracked_method, "FCPublish"))) {
1803  /* Gracefully ignore Adobe-specific historical artifact errors. */
1804  level = AV_LOG_WARNING;
1805  ret = 0;
1806  } else if (tracked_method && !strcmp(tracked_method, "getStreamLength")) {
1807  level = rt->live ? AV_LOG_DEBUG : AV_LOG_WARNING;
1808  ret = 0;
1809  } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1810  ret = handle_connect_error(s, tmpstr);
1811  if (!ret) {
1812  rt->do_reconnect = 1;
1813  level = AV_LOG_VERBOSE;
1814  }
1815  } else
1816  ret = AVERROR_UNKNOWN;
1817  av_log(s, level, "Server error: %s\n", tmpstr);
1818  }
1819 
1820  av_free(tracked_method);
1821  return ret;
1822 }
1823 
1825 {
1826  RTMPContext *rt = s->priv_data;
1827  PutByteContext pbc;
1828  RTMPPacket spkt = { 0 };
1829  int ret;
1830 
1831  // Send Stream Begin 1
1832  if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1833  RTMP_PT_PING, 0, 6)) < 0) {
1834  av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1835  return ret;
1836  }
1837 
1838  bytestream2_init_writer(&pbc, spkt.data, spkt.size);
1839  bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1840  bytestream2_put_be32(&pbc, rt->nb_streamid);
1841 
1842  ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1843  &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1844 
1845  ff_rtmp_packet_destroy(&spkt);
1846 
1847  return ret;
1848 }
1849 
1851  const char *status, const char *filename)
1852 {
1853  RTMPContext *rt = s->priv_data;
1854  RTMPPacket spkt = { 0 };
1855  char statusmsg[128];
1856  uint8_t *pp;
1857  int ret;
1858 
1859  if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1860  RTMP_PT_INVOKE, 0,
1861  RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1862  av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1863  return ret;
1864  }
1865 
1866  pp = spkt.data;
1867  spkt.extra = pkt->extra;
1868  ff_amf_write_string(&pp, "onStatus");
1869  ff_amf_write_number(&pp, 0);
1870  ff_amf_write_null(&pp);
1871 
1873  ff_amf_write_field_name(&pp, "level");
1874  ff_amf_write_string(&pp, "status");
1875  ff_amf_write_field_name(&pp, "code");
1876  ff_amf_write_string(&pp, status);
1877  ff_amf_write_field_name(&pp, "description");
1878  snprintf(statusmsg, sizeof(statusmsg),
1879  "%s is now published", filename);
1880  ff_amf_write_string(&pp, statusmsg);
1881  ff_amf_write_field_name(&pp, "details");
1882  ff_amf_write_string(&pp, filename);
1883  ff_amf_write_field_name(&pp, "clientid");
1884  snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1885  ff_amf_write_string(&pp, statusmsg);
1887 
1888  spkt.size = pp - spkt.data;
1889  ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1890  &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1891  ff_rtmp_packet_destroy(&spkt);
1892 
1893  return ret;
1894 }
1895 
1897 {
1898  RTMPContext *rt = s->priv_data;
1899  double seqnum;
1900  char filename[64];
1901  char command[64];
1902  int stringlen;
1903  char *pchar;
1904  const uint8_t *p = pkt->data;
1905  uint8_t *pp = NULL;
1906  RTMPPacket spkt = { 0 };
1907  GetByteContext gbc;
1908  int ret;
1909 
1910  bytestream2_init(&gbc, p, pkt->size);
1911  if (ff_amf_read_string(&gbc, command, sizeof(command),
1912  &stringlen)) {
1913  av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1914  return AVERROR_INVALIDDATA;
1915  }
1916 
1917  ret = ff_amf_read_number(&gbc, &seqnum);
1918  if (ret)
1919  return ret;
1920  ret = ff_amf_read_null(&gbc);
1921  if (ret)
1922  return ret;
1923  if (!strcmp(command, "FCPublish") ||
1924  !strcmp(command, "publish")) {
1925  ret = ff_amf_read_string(&gbc, filename,
1926  sizeof(filename), &stringlen);
1927  // check with url
1928  if (s->filename) {
1929  pchar = strrchr(s->filename, '/');
1930  if (!pchar) {
1932  "Unable to find / in url %s, bad format\n",
1933  s->filename);
1934  pchar = s->filename;
1935  }
1936  pchar++;
1937  if (strcmp(pchar, filename))
1938  av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1939  " %s\n", filename, pchar);
1940  }
1941  rt->state = STATE_RECEIVING;
1942  }
1943 
1944  if (!strcmp(command, "FCPublish")) {
1945  if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1946  RTMP_PT_INVOKE, 0,
1947  RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1948  av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1949  return ret;
1950  }
1951  pp = spkt.data;
1952  ff_amf_write_string(&pp, "onFCPublish");
1953  } else if (!strcmp(command, "publish")) {
1954  ret = write_begin(s);
1955  if (ret < 0)
1956  return ret;
1957 
1958  // Send onStatus(NetStream.Publish.Start)
1959  return write_status(s, pkt, "NetStream.Publish.Start",
1960  filename);
1961  } else if (!strcmp(command, "play")) {
1962  ret = write_begin(s);
1963  if (ret < 0)
1964  return ret;
1965  rt->state = STATE_SENDING;
1966  return write_status(s, pkt, "NetStream.Play.Start",
1967  filename);
1968  } else {
1969  if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1970  RTMP_PT_INVOKE, 0,
1971  RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1972  av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1973  return ret;
1974  }
1975  pp = spkt.data;
1976  ff_amf_write_string(&pp, "_result");
1977  ff_amf_write_number(&pp, seqnum);
1978  ff_amf_write_null(&pp);
1979  if (!strcmp(command, "createStream")) {
1980  rt->nb_streamid++;
1981  if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1982  rt->nb_streamid++; /* Values 0 and 2 are reserved */
1983  ff_amf_write_number(&pp, rt->nb_streamid);
1984  /* By now we don't control which streams are removed in
1985  * deleteStream. There is no stream creation control
1986  * if a client creates more than 2^32 - 2 streams. */
1987  }
1988  }
1989  spkt.size = pp - spkt.data;
1990  ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1991  &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
1992  ff_rtmp_packet_destroy(&spkt);
1993  return ret;
1994 }
1995 
1996 /**
1997  * Read the AMF_NUMBER response ("_result") to a function call
1998  * (e.g. createStream()). This response should be made up of the AMF_STRING
1999  * "result", a NULL object and then the response encoded as AMF_NUMBER. On a
2000  * successful response, we will return set the value to number (otherwise number
2001  * will not be changed).
2002  *
2003  * @return 0 if reading the value succeeds, negative value otherwiss
2004  */
2005 static int read_number_result(RTMPPacket *pkt, double *number)
2006 {
2007  // We only need to fit "_result" in this.
2008  uint8_t strbuffer[8];
2009  int stringlen;
2010  double numbuffer;
2011  GetByteContext gbc;
2012 
2013  bytestream2_init(&gbc, pkt->data, pkt->size);
2014 
2015  // Value 1/4: "_result" as AMF_STRING
2016  if (ff_amf_read_string(&gbc, strbuffer, sizeof(strbuffer), &stringlen))
2017  return AVERROR_INVALIDDATA;
2018  if (strcmp(strbuffer, "_result"))
2019  return AVERROR_INVALIDDATA;
2020  // Value 2/4: The callee reference number
2021  if (ff_amf_read_number(&gbc, &numbuffer))
2022  return AVERROR_INVALIDDATA;
2023  // Value 3/4: Null
2024  if (ff_amf_read_null(&gbc))
2025  return AVERROR_INVALIDDATA;
2026  // Value 4/4: The resonse as AMF_NUMBER
2027  if (ff_amf_read_number(&gbc, &numbuffer))
2028  return AVERROR_INVALIDDATA;
2029  else
2030  *number = numbuffer;
2031 
2032  return 0;
2033 }
2034 
2036 {
2037  RTMPContext *rt = s->priv_data;
2038  char *tracked_method = NULL;
2039  int ret = 0;
2040 
2041  if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
2042  return ret;
2043 
2044  if (!tracked_method) {
2045  /* Ignore this reply when the current method is not tracked. */
2046  return ret;
2047  }
2048 
2049  if (!strcmp(tracked_method, "connect")) {
2050  if (!rt->is_input) {
2051  if ((ret = gen_release_stream(s, rt)) < 0)
2052  goto fail;
2053 
2054  if ((ret = gen_fcpublish_stream(s, rt)) < 0)
2055  goto fail;
2056  } else {
2057  if ((ret = gen_server_bw(s, rt)) < 0)
2058  goto fail;
2059  }
2060 
2061  if ((ret = gen_create_stream(s, rt)) < 0)
2062  goto fail;
2063 
2064  if (rt->is_input) {
2065  /* Send the FCSubscribe command when the name of live
2066  * stream is defined by the user or if it's a live stream. */
2067  if (rt->subscribe) {
2068  if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
2069  goto fail;
2070  } else if (rt->live == -1) {
2071  if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
2072  goto fail;
2073  }
2074  }
2075  } else if (!strcmp(tracked_method, "createStream")) {
2076  double stream_id;
2077  if (read_number_result(pkt, &stream_id)) {
2078  av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
2079  } else {
2080  rt->stream_id = stream_id;
2081  }
2082 
2083  if (!rt->is_input) {
2084  if ((ret = gen_publish(s, rt)) < 0)
2085  goto fail;
2086  } else {
2087  if (rt->live != -1) {
2088  if ((ret = gen_get_stream_length(s, rt)) < 0)
2089  goto fail;
2090  }
2091  if ((ret = gen_play(s, rt)) < 0)
2092  goto fail;
2093  if ((ret = gen_buffer_time(s, rt)) < 0)
2094  goto fail;
2095  }
2096  } else if (!strcmp(tracked_method, "getStreamLength")) {
2097  if (read_number_result(pkt, &rt->duration)) {
2098  av_log(s, AV_LOG_WARNING, "Unexpected reply on getStreamLength()\n");
2099  }
2100  }
2101 
2102 fail:
2103  av_free(tracked_method);
2104  return ret;
2105 }
2106 
2108 {
2109  RTMPContext *rt = s->priv_data;
2110  const uint8_t *data_end = pkt->data + pkt->size;
2111  const uint8_t *ptr = pkt->data + RTMP_HEADER;
2112  uint8_t tmpstr[256];
2113  int i, t;
2114 
2115  for (i = 0; i < 2; i++) {
2116  t = ff_amf_tag_size(ptr, data_end);
2117  if (t < 0)
2118  return 1;
2119  ptr += t;
2120  }
2121 
2122  t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
2123  if (!t && !strcmp(tmpstr, "error")) {
2124  t = ff_amf_get_field_value(ptr, data_end,
2125  "description", tmpstr, sizeof(tmpstr));
2126  if (t || !tmpstr[0])
2127  t = ff_amf_get_field_value(ptr, data_end, "code",
2128  tmpstr, sizeof(tmpstr));
2129  if (!t)
2130  av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
2131  return -1;
2132  }
2133 
2134  t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
2135  if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
2136  if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
2137  if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
2138  if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
2139  if (!t && !strcmp(tmpstr, "NetStream.Seek.Notify")) rt->state = STATE_PLAYING;
2140 
2141  return 0;
2142 }
2143 
2145 {
2146  RTMPContext *rt = s->priv_data;
2147  int ret = 0;
2148 
2149  //TODO: check for the messages sent for wrong state?
2150  if (ff_amf_match_string(pkt->data, pkt->size, "_error")) {
2151  if ((ret = handle_invoke_error(s, pkt)) < 0)
2152  return ret;
2153  } else if (ff_amf_match_string(pkt->data, pkt->size, "_result")) {
2154  if ((ret = handle_invoke_result(s, pkt)) < 0)
2155  return ret;
2156  } else if (ff_amf_match_string(pkt->data, pkt->size, "onStatus")) {
2157  if ((ret = handle_invoke_status(s, pkt)) < 0)
2158  return ret;
2159  } else if (ff_amf_match_string(pkt->data, pkt->size, "onBWDone")) {
2160  if ((ret = gen_check_bw(s, rt)) < 0)
2161  return ret;
2162  } else if (ff_amf_match_string(pkt->data, pkt->size, "releaseStream") ||
2163  ff_amf_match_string(pkt->data, pkt->size, "FCPublish") ||
2164  ff_amf_match_string(pkt->data, pkt->size, "publish") ||
2165  ff_amf_match_string(pkt->data, pkt->size, "play") ||
2166  ff_amf_match_string(pkt->data, pkt->size, "_checkbw") ||
2167  ff_amf_match_string(pkt->data, pkt->size, "createStream")) {
2168  if ((ret = send_invoke_response(s, pkt)) < 0)
2169  return ret;
2170  }
2171 
2172  return ret;
2173 }
2174 
2175 static int update_offset(RTMPContext *rt, int size)
2176 {
2177  int old_flv_size;
2178 
2179  // generate packet header and put data into buffer for FLV demuxer
2180  if (rt->flv_off < rt->flv_size) {
2181  // There is old unread data in the buffer, thus append at the end
2182  old_flv_size = rt->flv_size;
2183  rt->flv_size += size;
2184  } else {
2185  // All data has been read, write the new data at the start of the buffer
2186  old_flv_size = 0;
2187  rt->flv_size = size;
2188  rt->flv_off = 0;
2189  }
2190 
2191  return old_flv_size;
2192 }
2193 
2194 static int append_flv_data(RTMPContext *rt, RTMPPacket *pkt, int skip)
2195 {
2196  int old_flv_size, ret;
2197  PutByteContext pbc;
2198  const uint8_t *data = pkt->data + skip;
2199  const int size = pkt->size - skip;
2200  uint32_t ts = pkt->timestamp;
2201 
2202  if (pkt->type == RTMP_PT_AUDIO) {
2203  rt->has_audio = 1;
2204  } else if (pkt->type == RTMP_PT_VIDEO) {
2205  rt->has_video = 1;
2206  }
2207 
2208  old_flv_size = update_offset(rt, size + 15);
2209 
2210  if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2211  rt->flv_size = rt->flv_off = 0;
2212  return ret;
2213  }
2214  bytestream2_init_writer(&pbc, rt->flv_data, rt->flv_size);
2215  bytestream2_skip_p(&pbc, old_flv_size);
2216  bytestream2_put_byte(&pbc, pkt->type);
2217  bytestream2_put_be24(&pbc, size);
2218  bytestream2_put_be24(&pbc, ts);
2219  bytestream2_put_byte(&pbc, ts >> 24);
2220  bytestream2_put_be24(&pbc, 0);
2221  bytestream2_put_buffer(&pbc, data, size);
2222  bytestream2_put_be32(&pbc, size + RTMP_HEADER);
2223 
2224  return 0;
2225 }
2226 
2228 {
2229  RTMPContext *rt = s->priv_data;
2230  uint8_t commandbuffer[64];
2231  char statusmsg[128];
2232  int stringlen, ret, skip = 0;
2233  GetByteContext gbc;
2234 
2235  bytestream2_init(&gbc, pkt->data, pkt->size);
2236  if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
2237  &stringlen))
2238  return AVERROR_INVALIDDATA;
2239 
2240  if (!strcmp(commandbuffer, "onMetaData")) {
2241  // metadata properties should be stored in a mixed array
2242  if (bytestream2_get_byte(&gbc) == AMF_DATA_TYPE_MIXEDARRAY) {
2243  // We have found a metaData Array so flv can determine the streams
2244  // from this.
2245  rt->received_metadata = 1;
2246  // skip 32-bit max array index
2247  bytestream2_skip(&gbc, 4);
2248  while (bytestream2_get_bytes_left(&gbc) > 3) {
2249  if (ff_amf_get_string(&gbc, statusmsg, sizeof(statusmsg),
2250  &stringlen))
2251  return AVERROR_INVALIDDATA;
2252  // We do not care about the content of the property (yet).
2253  stringlen = ff_amf_tag_size(gbc.buffer, gbc.buffer_end);
2254  if (stringlen < 0)
2255  return AVERROR_INVALIDDATA;
2256  bytestream2_skip(&gbc, stringlen);
2257 
2258  // The presence of the following properties indicates that the
2259  // respective streams are present.
2260  if (!strcmp(statusmsg, "videocodecid")) {
2261  rt->has_video = 1;
2262  }
2263  if (!strcmp(statusmsg, "audiocodecid")) {
2264  rt->has_audio = 1;
2265  }
2266  }
2267  if (bytestream2_get_be24(&gbc) != AMF_END_OF_OBJECT)
2268  return AVERROR_INVALIDDATA;
2269  }
2270  }
2271 
2272  // Skip the @setDataFrame string and validate it is a notification
2273  if (!strcmp(commandbuffer, "@setDataFrame")) {
2274  skip = gbc.buffer - pkt->data;
2275  ret = ff_amf_read_string(&gbc, statusmsg,
2276  sizeof(statusmsg), &stringlen);
2277  if (ret < 0)
2278  return AVERROR_INVALIDDATA;
2279  }
2280 
2281  return append_flv_data(rt, pkt, skip);
2282 }
2283 
2284 /**
2285  * Parse received packet and possibly perform some action depending on
2286  * the packet contents.
2287  * @return 0 for no errors, negative values for serious errors which prevent
2288  * further communications, positive values for uncritical errors
2289  */
2291 {
2292  int ret;
2293 
2294 #ifdef DEBUG
2295  ff_rtmp_packet_dump(s, pkt);
2296 #endif
2297 
2298  switch (pkt->type) {
2299  case RTMP_PT_BYTES_READ:
2300  av_log(s, AV_LOG_TRACE, "received bytes read report\n");
2301  break;
2302  case RTMP_PT_CHUNK_SIZE:
2303  if ((ret = handle_chunk_size(s, pkt)) < 0)
2304  return ret;
2305  break;
2306  case RTMP_PT_PING:
2307  if ((ret = handle_ping(s, pkt)) < 0)
2308  return ret;
2309  break;
2310  case RTMP_PT_CLIENT_BW:
2311  if ((ret = handle_client_bw(s, pkt)) < 0)
2312  return ret;
2313  break;
2314  case RTMP_PT_SERVER_BW:
2315  if ((ret = handle_server_bw(s, pkt)) < 0)
2316  return ret;
2317  break;
2318  case RTMP_PT_INVOKE:
2319  if ((ret = handle_invoke(s, pkt)) < 0)
2320  return ret;
2321  break;
2322  case RTMP_PT_VIDEO:
2323  case RTMP_PT_AUDIO:
2324  case RTMP_PT_METADATA:
2325  case RTMP_PT_NOTIFY:
2326  /* Audio, Video and Metadata packets are parsed in get_packet() */
2327  break;
2328  default:
2329  av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2330  break;
2331  }
2332  return 0;
2333 }
2334 
2336 {
2337  int ret, old_flv_size, type;
2338  const uint8_t *next;
2339  uint8_t *p;
2340  uint32_t size;
2341  uint32_t ts, cts, pts = 0;
2342 
2343  old_flv_size = update_offset(rt, pkt->size);
2344 
2345  if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0) {
2346  rt->flv_size = rt->flv_off = 0;
2347  return ret;
2348  }
2349 
2350  next = pkt->data;
2351  p = rt->flv_data + old_flv_size;
2352 
2353  /* copy data while rewriting timestamps */
2354  ts = pkt->timestamp;
2355 
2356  while (next - pkt->data < pkt->size - RTMP_HEADER) {
2357  type = bytestream_get_byte(&next);
2358  size = bytestream_get_be24(&next);
2359  cts = bytestream_get_be24(&next);
2360  cts |= bytestream_get_byte(&next) << 24;
2361  if (!pts)
2362  pts = cts;
2363  ts += cts - pts;
2364  pts = cts;
2365  if (size + 3 + 4 > pkt->data + pkt->size - next)
2366  break;
2367  bytestream_put_byte(&p, type);
2368  bytestream_put_be24(&p, size);
2369  bytestream_put_be24(&p, ts);
2370  bytestream_put_byte(&p, ts >> 24);
2371  memcpy(p, next, size + 3 + 4);
2372  p += size + 3;
2373  bytestream_put_be32(&p, size + RTMP_HEADER);
2374  next += size + 3 + 4;
2375  }
2376  if (p != rt->flv_data + rt->flv_size) {
2377  av_log(NULL, AV_LOG_WARNING, "Incomplete flv packets in "
2378  "RTMP_PT_METADATA packet\n");
2379  rt->flv_size = p - rt->flv_data;
2380  }
2381 
2382  return 0;
2383 }
2384 
2385 /**
2386  * Interact with the server by receiving and sending RTMP packets until
2387  * there is some significant data (media data or expected status notification).
2388  *
2389  * @param s reading context
2390  * @param for_header non-zero value tells function to work until it
2391  * gets notification from the server that playing has been started,
2392  * otherwise function will work until some media data is received (or
2393  * an error happens)
2394  * @return 0 for successful operation, negative value in case of error
2395  */
2396 static int get_packet(URLContext *s, int for_header)
2397 {
2398  RTMPContext *rt = s->priv_data;
2399  int ret;
2400 
2401  if (rt->state == STATE_STOPPED)
2402  return AVERROR_EOF;
2403 
2404  for (;;) {
2405  RTMPPacket rpkt = { 0 };
2406  if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
2407  rt->in_chunk_size, &rt->prev_pkt[0],
2408  &rt->nb_prev_pkt[0])) <= 0) {
2409  if (ret == 0) {
2410  return AVERROR(EAGAIN);
2411  } else {
2412  return AVERROR(EIO);
2413  }
2414  }
2415 
2416  // Track timestamp for later use
2417  rt->last_timestamp = rpkt.timestamp;
2418 
2419  rt->bytes_read += ret;
2420  if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
2421  av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
2422  if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2423  return ret;
2424  rt->last_bytes_read = rt->bytes_read;
2425  }
2426 
2427  ret = rtmp_parse_result(s, rt, &rpkt);
2428 
2429  // At this point we must check if we are in the seek state and continue
2430  // with the next packet. handle_invoke will get us out of this state
2431  // when the right message is encountered
2432  if (rt->state == STATE_SEEKING) {
2433  ff_rtmp_packet_destroy(&rpkt);
2434  // We continue, let the natural flow of things happen:
2435  // AVERROR(EAGAIN) or handle_invoke gets us out of here
2436  continue;
2437  }
2438 
2439  if (ret < 0) {//serious error in current packet
2440  ff_rtmp_packet_destroy(&rpkt);
2441  return ret;
2442  }
2443  if (rt->do_reconnect && for_header) {
2444  ff_rtmp_packet_destroy(&rpkt);
2445  return 0;
2446  }
2447  if (rt->state == STATE_STOPPED) {
2448  ff_rtmp_packet_destroy(&rpkt);
2449  return AVERROR_EOF;
2450  }
2451  if (for_header && (rt->state == STATE_PLAYING ||
2452  rt->state == STATE_PUBLISHING ||
2453  rt->state == STATE_SENDING ||
2454  rt->state == STATE_RECEIVING)) {
2455  ff_rtmp_packet_destroy(&rpkt);
2456  return 0;
2457  }
2458  if (!rpkt.size || !rt->is_input) {
2459  ff_rtmp_packet_destroy(&rpkt);
2460  continue;
2461  }
2462  if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO) {
2463  ret = append_flv_data(rt, &rpkt, 0);
2464  ff_rtmp_packet_destroy(&rpkt);
2465  return ret;
2466  } else if (rpkt.type == RTMP_PT_NOTIFY) {
2467  ret = handle_notify(s, &rpkt);
2468  ff_rtmp_packet_destroy(&rpkt);
2469  return ret;
2470  } else if (rpkt.type == RTMP_PT_METADATA) {
2471  ret = handle_metadata(rt, &rpkt);
2472  ff_rtmp_packet_destroy(&rpkt);
2473  return 0;
2474  }
2475  ff_rtmp_packet_destroy(&rpkt);
2476  }
2477 }
2478 
2480 {
2481  RTMPContext *rt = h->priv_data;
2482  int ret = 0, i, j;
2483 
2484  if (!rt->is_input) {
2485  rt->flv_data = NULL;
2486  if (rt->out_pkt.size)
2488  if (rt->state > STATE_FCPUBLISH)
2489  ret = gen_fcunpublish_stream(h, rt);
2490  }
2491  if (rt->state > STATE_HANDSHAKED)
2492  ret = gen_delete_stream(h, rt);
2493  for (i = 0; i < 2; i++) {
2494  for (j = 0; j < rt->nb_prev_pkt[i]; j++)
2495  ff_rtmp_packet_destroy(&rt->prev_pkt[i][j]);
2496  av_freep(&rt->prev_pkt[i]);
2497  }
2498 
2500  av_freep(&rt->flv_data);
2501  ffurl_close(rt->stream);
2502  return ret;
2503 }
2504 
2505 /**
2506  * Insert a fake onMetadata packet into the FLV stream to notify the FLV
2507  * demuxer about the duration of the stream.
2508  *
2509  * This should only be done if there was no real onMetadata packet sent by the
2510  * server at the start of the stream and if we were able to retrieve a valid
2511  * duration via a getStreamLength call.
2512  *
2513  * @return 0 for successful operation, negative value in case of error
2514  */
2516 {
2517  // We need to insert the metdata packet directly after the FLV
2518  // header, i.e. we need to move all other already read data by the
2519  // size of our fake metadata packet.
2520 
2521  uint8_t* p;
2522  // Keep old flv_data pointer
2523  uint8_t* old_flv_data = rt->flv_data;
2524  // Allocate a new flv_data pointer with enough space for the additional package
2525  if (!(rt->flv_data = av_malloc(rt->flv_size + 55))) {
2526  rt->flv_data = old_flv_data;
2527  return AVERROR(ENOMEM);
2528  }
2529 
2530  // Copy FLV header
2531  memcpy(rt->flv_data, old_flv_data, 13);
2532  // Copy remaining packets
2533  memcpy(rt->flv_data + 13 + 55, old_flv_data + 13, rt->flv_size - 13);
2534  // Increase the size by the injected packet
2535  rt->flv_size += 55;
2536  // Delete the old FLV data
2537  av_freep(&old_flv_data);
2538 
2539  p = rt->flv_data + 13;
2540  bytestream_put_byte(&p, FLV_TAG_TYPE_META);
2541  bytestream_put_be24(&p, 40); // size of data part (sum of all parts below)
2542  bytestream_put_be24(&p, 0); // timestamp
2543  bytestream_put_be32(&p, 0); // reserved
2544 
2545  // first event name as a string
2546  bytestream_put_byte(&p, AMF_DATA_TYPE_STRING);
2547  // "onMetaData" as AMF string
2548  bytestream_put_be16(&p, 10);
2549  bytestream_put_buffer(&p, "onMetaData", 10);
2550 
2551  // mixed array (hash) with size and string/type/data tuples
2552  bytestream_put_byte(&p, AMF_DATA_TYPE_MIXEDARRAY);
2553  bytestream_put_be32(&p, 1); // metadata_count
2554 
2555  // "duration" as AMF string
2556  bytestream_put_be16(&p, 8);
2557  bytestream_put_buffer(&p, "duration", 8);
2558  bytestream_put_byte(&p, AMF_DATA_TYPE_NUMBER);
2559  bytestream_put_be64(&p, av_double2int(rt->duration));
2560 
2561  // Finalise object
2562  bytestream_put_be16(&p, 0); // Empty string
2563  bytestream_put_byte(&p, AMF_END_OF_OBJECT);
2564  bytestream_put_be32(&p, 40 + RTMP_HEADER); // size of data part (sum of all parts above)
2565 
2566  return 0;
2567 }
2568 
2569 /**
2570  * Open RTMP connection and verify that the stream can be played.
2571  *
2572  * URL syntax: rtmp://server[:port][/app][/playpath]
2573  * where 'app' is first one or two directories in the path
2574  * (e.g. /ondemand/, /flash/live/, etc.)
2575  * and 'playpath' is a file name (the rest of the path,
2576  * may be prefixed with "mp4:")
2577  */
2578 static int rtmp_open(URLContext *s, const char *uri, int flags)
2579 {
2580  RTMPContext *rt = s->priv_data;
2581  char proto[8], hostname[256], path[1024], auth[100], *fname;
2582  char *old_app, *qmark, *n, fname_buffer[1024];
2583  uint8_t buf[2048];
2584  int port;
2585  AVDictionary *opts = NULL;
2586  int ret;
2587 
2588  if (rt->listen_timeout > 0)
2589  rt->listen = 1;
2590 
2591  rt->is_input = !(flags & AVIO_FLAG_WRITE);
2592 
2593  av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2594  hostname, sizeof(hostname), &port,
2595  path, sizeof(path), s->filename);
2596 
2597  n = strchr(path, ' ');
2598  if (n) {
2600  "Detected librtmp style URL parameters, these aren't supported "
2601  "by the libavformat internal RTMP handler currently enabled. "
2602  "See the documentation for the correct way to pass parameters.\n");
2603  *n = '\0'; // Trim not supported part
2604  }
2605 
2606  if (auth[0]) {
2607  char *ptr = strchr(auth, ':');
2608  if (ptr) {
2609  *ptr = '\0';
2610  av_strlcpy(rt->username, auth, sizeof(rt->username));
2611  av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2612  }
2613  }
2614 
2615  if (rt->listen && strcmp(proto, "rtmp")) {
2616  av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2617  proto);
2618  return AVERROR(EINVAL);
2619  }
2620  if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2621  if (!strcmp(proto, "rtmpts"))
2622  av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2623 
2624  /* open the http tunneling connection */
2625  ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
2626  } else if (!strcmp(proto, "rtmps")) {
2627  /* open the tls connection */
2628  if (port < 0)
2629  port = RTMPS_DEFAULT_PORT;
2630  ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
2631  } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2632  if (!strcmp(proto, "rtmpte"))
2633  av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2634 
2635  /* open the encrypted connection */
2636  ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2637  rt->encrypted = 1;
2638  } else {
2639  /* open the tcp connection */
2640  if (port < 0)
2641  port = RTMP_DEFAULT_PORT;
2642  if (rt->listen)
2643  ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2644  "?listen&listen_timeout=%d",
2645  rt->listen_timeout * 1000);
2646  else
2647  ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
2648  }
2649 
2650 reconnect:
2651  if ((ret = ffurl_open_whitelist(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
2652  &s->interrupt_callback, &opts,
2653  s->protocol_whitelist)) < 0) {
2654  av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
2655  goto fail;
2656  }
2657 
2658  if (rt->swfverify) {
2659  if ((ret = rtmp_calc_swfhash(s)) < 0)
2660  goto fail;
2661  }
2662 
2663  rt->state = STATE_START;
2664  if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2665  goto fail;
2666  if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
2667  goto fail;
2668 
2669  rt->out_chunk_size = 128;
2670  rt->in_chunk_size = 128; // Probably overwritten later
2671  rt->state = STATE_HANDSHAKED;
2672 
2673  // Keep the application name when it has been defined by the user.
2674  old_app = rt->app;
2675 
2676  rt->app = av_malloc(APP_MAX_LENGTH);
2677  if (!rt->app) {
2678  ret = AVERROR(ENOMEM);
2679  goto fail;
2680  }
2681 
2682  //extract "app" part from path
2683  qmark = strchr(path, '?');
2684  if (qmark && strstr(qmark, "slist=")) {
2685  char* amp;
2686  // After slist we have the playpath, the full path is used as app
2687  av_strlcpy(rt->app, path + 1, APP_MAX_LENGTH);
2688  fname = strstr(path, "slist=") + 6;
2689  // Strip any further query parameters from fname
2690  amp = strchr(fname, '&');
2691  if (amp) {
2692  av_strlcpy(fname_buffer, fname, FFMIN(amp - fname + 1,
2693  sizeof(fname_buffer)));
2694  fname = fname_buffer;
2695  }
2696  } else if (!strncmp(path, "/ondemand/", 10)) {
2697  fname = path + 10;
2698  memcpy(rt->app, "ondemand", 9);
2699  } else {
2700  char *next = *path ? path + 1 : path;
2701  char *p = strchr(next, '/');
2702  if (!p) {
2703  if (old_app) {
2704  // If name of application has been defined by the user, assume that
2705  // playpath is provided in the URL
2706  fname = next;
2707  } else {
2708  fname = NULL;
2709  av_strlcpy(rt->app, next, APP_MAX_LENGTH);
2710  }
2711  } else {
2712  // make sure we do not mismatch a playpath for an application instance
2713  char *c = strchr(p + 1, ':');
2714  fname = strchr(p + 1, '/');
2715  if (!fname || (c && c < fname)) {
2716  fname = p + 1;
2717  av_strlcpy(rt->app, path + 1, FFMIN(p - path, APP_MAX_LENGTH));
2718  } else {
2719  fname++;
2720  av_strlcpy(rt->app, path + 1, FFMIN(fname - path - 1, APP_MAX_LENGTH));
2721  }
2722  }
2723  }
2724 
2725  if (old_app) {
2726  // The name of application has been defined by the user, override it.
2727  if (strlen(old_app) >= APP_MAX_LENGTH) {
2728  ret = AVERROR(EINVAL);
2729  goto fail;
2730  }
2731  av_free(rt->app);
2732  rt->app = old_app;
2733  }
2734 
2735  if (!rt->playpath) {
2737  if (!rt->playpath) {
2738  ret = AVERROR(ENOMEM);
2739  goto fail;
2740  }
2741 
2742  if (fname) {
2743  int len = strlen(fname);
2744  if (!strchr(fname, ':') && len >= 4 &&
2745  (!strcmp(fname + len - 4, ".f4v") ||
2746  !strcmp(fname + len - 4, ".mp4"))) {
2747  memcpy(rt->playpath, "mp4:", 5);
2748  } else {
2749  if (len >= 4 && !strcmp(fname + len - 4, ".flv"))
2750  fname[len - 4] = '\0';
2751  rt->playpath[0] = 0;
2752  }
2754  } else {
2755  rt->playpath[0] = '\0';
2756  }
2757  }
2758 
2759  if (!rt->tcurl) {
2761  if (!rt->tcurl) {
2762  ret = AVERROR(ENOMEM);
2763  goto fail;
2764  }
2765  ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2766  port, "/%s", rt->app);
2767  }
2768 
2769  if (!rt->flashver) {
2771  if (!rt->flashver) {
2772  ret = AVERROR(ENOMEM);
2773  goto fail;
2774  }
2775  if (rt->is_input) {
2776  snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2779  } else {
2781  "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2782  }
2783  }
2784 
2785  rt->client_report_size = 1048576;
2786  rt->bytes_read = 0;
2787  rt->has_audio = 0;
2788  rt->has_video = 0;
2789  rt->received_metadata = 0;
2790  rt->last_bytes_read = 0;
2791  rt->server_bw = 2500000;
2792  rt->duration = 0;
2793 
2794  av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
2795  proto, path, rt->app, rt->playpath);
2796  if (!rt->listen) {
2797  if ((ret = gen_connect(s, rt)) < 0)
2798  goto fail;
2799  } else {
2800  if ((ret = read_connect(s, s->priv_data)) < 0)
2801  goto fail;
2802  }
2803 
2804  do {
2805  ret = get_packet(s, 1);
2806  } while (ret == AVERROR(EAGAIN));
2807  if (ret < 0)
2808  goto fail;
2809 
2810  if (rt->do_reconnect) {
2811  int i;
2812  ffurl_close(rt->stream);
2813  rt->stream = NULL;
2814  rt->do_reconnect = 0;
2815  rt->nb_invokes = 0;
2816  for (i = 0; i < 2; i++)
2817  memset(rt->prev_pkt[i], 0,
2818  sizeof(**rt->prev_pkt) * rt->nb_prev_pkt[i]);
2820  goto reconnect;
2821  }
2822 
2823  if (rt->is_input) {
2824  // generate FLV header for demuxer
2825  rt->flv_size = 13;
2826  if ((ret = av_reallocp(&rt->flv_data, rt->flv_size)) < 0)
2827  goto fail;
2828  rt->flv_off = 0;
2829  memcpy(rt->flv_data, "FLV\1\0\0\0\0\011\0\0\0\0", rt->flv_size);
2830 
2831  // Read packets until we reach the first A/V packet or read metadata.
2832  // If there was a metadata package in front of the A/V packets, we can
2833  // build the FLV header from this. If we do not receive any metadata,
2834  // the FLV decoder will allocate the needed streams when their first
2835  // audio or video packet arrives.
2836  while (!rt->has_audio && !rt->has_video && !rt->received_metadata) {
2837  if ((ret = get_packet(s, 0)) < 0)
2838  goto fail;
2839  }
2840 
2841  // Either after we have read the metadata or (if there is none) the
2842  // first packet of an A/V stream, we have a better knowledge about the
2843  // streams, so set the FLV header accordingly.
2844  if (rt->has_audio) {
2846  }
2847  if (rt->has_video) {
2849  }
2850 
2851  // If we received the first packet of an A/V stream and no metadata but
2852  // the server returned a valid duration, create a fake metadata packet
2853  // to inform the FLV decoder about the duration.
2854  if (!rt->received_metadata && rt->duration > 0) {
2855  if ((ret = inject_fake_duration_metadata(rt)) < 0)
2856  goto fail;
2857  }
2858  } else {
2859  rt->flv_size = 0;
2860  rt->flv_data = NULL;
2861  rt->flv_off = 0;
2862  rt->skip_bytes = 13;
2863  }
2864 
2866  s->is_streamed = 1;
2867  return 0;
2868 
2869 fail:
2870  av_dict_free(&opts);
2871  rtmp_close(s);
2872  return ret;
2873 }
2874 
2875 static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2876 {
2877  RTMPContext *rt = s->priv_data;
2878  int orig_size = size;
2879  int ret;
2880 
2881  while (size > 0) {
2882  int data_left = rt->flv_size - rt->flv_off;
2883 
2884  if (data_left >= size) {
2885  memcpy(buf, rt->flv_data + rt->flv_off, size);
2886  rt->flv_off += size;
2887  return orig_size;
2888  }
2889  if (data_left > 0) {
2890  memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2891  buf += data_left;
2892  size -= data_left;
2893  rt->flv_off = rt->flv_size;
2894  return data_left;
2895  }
2896  if ((ret = get_packet(s, 0)) < 0)
2897  return ret;
2898  }
2899  return orig_size;
2900 }
2901 
2902 static int64_t rtmp_seek(URLContext *s, int stream_index, int64_t timestamp,
2903  int flags)
2904 {
2905  RTMPContext *rt = s->priv_data;
2906  int ret;
2907  av_log(s, AV_LOG_DEBUG,
2908  "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2909  stream_index, timestamp, flags);
2910  if ((ret = gen_seek(s, rt, timestamp)) < 0) {
2911  av_log(s, AV_LOG_ERROR,
2912  "Unable to send seek command on stream index %d at timestamp "
2913  "%"PRId64" with flags %08x\n",
2914  stream_index, timestamp, flags);
2915  return ret;
2916  }
2917  rt->flv_off = rt->flv_size;
2918  rt->state = STATE_SEEKING;
2919  return timestamp;
2920 }
2921 
2922 static int rtmp_pause(URLContext *s, int pause)
2923 {
2924  RTMPContext *rt = s->priv_data;
2925  int ret;
2926  av_log(s, AV_LOG_DEBUG, "Pause at timestamp %d\n",
2927  rt->last_timestamp);
2928  if ((ret = gen_pause(s, rt, pause, rt->last_timestamp)) < 0) {
2929  av_log(s, AV_LOG_ERROR, "Unable to send pause command at timestamp %d\n",
2930  rt->last_timestamp);
2931  return ret;
2932  }
2933  return 0;
2934 }
2935 
2936 static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
2937 {
2938  RTMPContext *rt = s->priv_data;
2939  int size_temp = size;
2940  int pktsize, pkttype, copy;
2941  uint32_t ts;
2942  const uint8_t *buf_temp = buf;
2943  uint8_t c;
2944  int ret;
2945 
2946  do {
2947  if (rt->skip_bytes) {
2948  int skip = FFMIN(rt->skip_bytes, size_temp);
2949  buf_temp += skip;
2950  size_temp -= skip;
2951  rt->skip_bytes -= skip;
2952  continue;
2953  }
2954 
2955  if (rt->flv_header_bytes < RTMP_HEADER) {
2956  const uint8_t *header = rt->flv_header;
2957  int channel = RTMP_AUDIO_CHANNEL;
2958 
2959  copy = FFMIN(RTMP_HEADER - rt->flv_header_bytes, size_temp);
2960  bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2961  rt->flv_header_bytes += copy;
2962  size_temp -= copy;
2963  if (rt->flv_header_bytes < RTMP_HEADER)
2964  break;
2965 
2966  pkttype = bytestream_get_byte(&header);
2967  pktsize = bytestream_get_be24(&header);
2968  ts = bytestream_get_be24(&header);
2969  ts |= bytestream_get_byte(&header) << 24;
2970  bytestream_get_be24(&header);
2971  rt->flv_size = pktsize;
2972 
2973  if (pkttype == RTMP_PT_VIDEO)
2974  channel = RTMP_VIDEO_CHANNEL;
2975 
2976  if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2977  pkttype == RTMP_PT_NOTIFY) {
2978  if ((ret = ff_rtmp_check_alloc_array(&rt->prev_pkt[1],
2979  &rt->nb_prev_pkt[1],
2980  channel)) < 0)
2981  return ret;
2982  // Force sending a full 12 bytes header by clearing the
2983  // channel id, to make it not match a potential earlier
2984  // packet in the same channel.
2985  rt->prev_pkt[1][channel].channel_id = 0;
2986  }
2987 
2988  //this can be a big packet, it's better to send it right here
2989  if ((ret = ff_rtmp_packet_create(&rt->out_pkt, channel,
2990  pkttype, ts, pktsize)) < 0)
2991  return ret;
2992 
2993  rt->out_pkt.extra = rt->stream_id;
2994  rt->flv_data = rt->out_pkt.data;
2995  }
2996 
2997  copy = FFMIN(rt->flv_size - rt->flv_off, size_temp);
2998  bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, copy);
2999  rt->flv_off += copy;
3000  size_temp -= copy;
3001 
3002  if (rt->flv_off == rt->flv_size) {
3003  rt->skip_bytes = 4;
3004 
3005  if (rt->out_pkt.type == RTMP_PT_NOTIFY) {
3006  // For onMetaData and |RtmpSampleAccess packets, we want
3007  // @setDataFrame prepended to the packet before it gets sent.
3008  // However, not all RTMP_PT_NOTIFY packets (e.g., onTextData
3009  // and onCuePoint).
3010  uint8_t commandbuffer[64];
3011  int stringlen = 0;
3012  GetByteContext gbc;
3013 
3014  bytestream2_init(&gbc, rt->flv_data, rt->flv_size);
3015  if (!ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
3016  &stringlen)) {
3017  if (!strcmp(commandbuffer, "onMetaData") ||
3018  !strcmp(commandbuffer, "|RtmpSampleAccess")) {
3019  uint8_t *ptr;
3020  if ((ret = av_reallocp(&rt->out_pkt.data, rt->out_pkt.size + 16)) < 0) {
3021  rt->flv_size = rt->flv_off = rt->flv_header_bytes = 0;
3022  return ret;
3023  }
3024  memmove(rt->out_pkt.data + 16, rt->out_pkt.data, rt->out_pkt.size);
3025  rt->out_pkt.size += 16;
3026  ptr = rt->out_pkt.data;
3027  ff_amf_write_string(&ptr, "@setDataFrame");
3028  }
3029  }
3030  }
3031 
3032  if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
3033  return ret;
3034  rt->flv_size = 0;
3035  rt->flv_off = 0;
3036  rt->flv_header_bytes = 0;
3037  rt->flv_nb_packets++;
3038  }
3039  } while (buf_temp - buf < size);
3040 
3041  if (rt->flv_nb_packets < rt->flush_interval)
3042  return size;
3043  rt->flv_nb_packets = 0;
3044 
3045  /* set stream into nonblocking mode */
3047 
3048  /* try to read one byte from the stream */
3049  ret = ffurl_read(rt->stream, &c, 1);
3050 
3051  /* switch the stream back into blocking mode */
3052  rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
3053 
3054  if (ret == AVERROR(EAGAIN)) {
3055  /* no incoming data to handle */
3056  return size;
3057  } else if (ret < 0) {
3058  return ret;
3059  } else if (ret == 1) {
3060  RTMPPacket rpkt = { 0 };
3061 
3062  if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
3063  rt->in_chunk_size,
3064  &rt->prev_pkt[0],
3065  &rt->nb_prev_pkt[0], c)) <= 0)
3066  return ret;
3067 
3068  if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
3069  return ret;
3070 
3071  ff_rtmp_packet_destroy(&rpkt);
3072  }
3073 
3074  return size;
3075 }
3076 
3077 #define OFFSET(x) offsetof(RTMPContext, x)
3078 #define DEC AV_OPT_FLAG_DECODING_PARAM
3079 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3080 
3081 static const AVOption rtmp_options[] = {
3082  {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3083  {"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},
3084  {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3085  {"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},
3086  {"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},
3087  {"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"},
3088  {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
3089  {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
3090  {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
3091  {"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},
3092  {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
3093  {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3094  {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
3095  {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
3096  {"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},
3097  {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
3098  {"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},
3099  {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3100  {"listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
3101  {"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" },
3102  { NULL },
3103 };
3104 
3105 #define RTMP_PROTOCOL(flavor) \
3106 static const AVClass flavor##_class = { \
3107  .class_name = #flavor, \
3108  .item_name = av_default_item_name, \
3109  .option = rtmp_options, \
3110  .version = LIBAVUTIL_VERSION_INT, \
3111 }; \
3112  \
3113 URLProtocol ff_##flavor##_protocol = { \
3114  .name = #flavor, \
3115  .url_open = rtmp_open, \
3116  .url_read = rtmp_read, \
3117  .url_read_seek = rtmp_seek, \
3118  .url_read_pause = rtmp_pause, \
3119  .url_write = rtmp_write, \
3120  .url_close = rtmp_close, \
3121  .priv_data_size = sizeof(RTMPContext), \
3122  .flags = URL_PROTOCOL_FLAG_NETWORK, \
3123  .priv_data_class= &flavor##_class, \
3124 };
3125 
3126 
3127 RTMP_PROTOCOL(rtmp)
3128 RTMP_PROTOCOL(rtmpe)
3129 RTMP_PROTOCOL(rtmps)
3130 RTMP_PROTOCOL(rtmpt)
3131 RTMP_PROTOCOL(rtmpte)
3132 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:4029
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:2875
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:245
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:2936
static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
Definition: rtmpproto.c:1785
enum AVCodecID id
Definition: mxfenc.c:104
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:2144
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:259
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:433
#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:537
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:538
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:501
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:3078
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:1416
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:558
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:2194
#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
static void inflate(uint8_t *dst, const uint8_t *p1, int width, int threshold, const uint8_t *coordinates[], int coord)
Definition: vf_neighbor.c:129
const uint8_t * buffer
Definition: bytestream.h:34
int ff_rtmpe_compute_secret_key(URLContext *h, const uint8_t *serverdata, const uint8_t *clientdata, int type)
Compute the shared secret key and initialize the RC4 encryption.
Definition: rtmpcrypt.c:145
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:155
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:1196
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:1596
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:1850
static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
Definition: rtmpproto.c:1550
#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:2515
const char * protocol_whitelist
Definition: url.h:50
#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:2107
ClientState
RTMP protocol handler state.
Definition: rtmpproto.c:59
uint8_t hash[HASH_SIZE]
Definition: movenc-test.c:57
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
int out_size
Definition: movenc-test.c:55
#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:80
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:2922
#define RTMP_PROTOCOL(flavor)
Definition: rtmpproto.c:3105
#define OFFSET(x)
Definition: rtmpproto.c:3077
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:2290
#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:96
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:134
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:2479
int nb_streamid
The next stream id to return on createStream calls.
Definition: rtmpproto.c:126
#define ENC
Definition: rtmpproto.c:3079
#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:1396
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:2902
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
#define src
Definition: vp9dsp.c:530
the broadcast has been stopped
Definition: rtmpproto.c:68
char * swfhash
SHA256 hash of the decompressed SWF file (32 bytes)
Definition: rtmpproto.c:109
char swfverification[42]
hash of the SWF verification
Definition: rtmpproto.c:114
int nb_tracked_methods
number of tracked methods
Definition: rtmpproto.c:122
offset must point to a pointer immediately followed by an int for the length
Definition: opt.h:229
int ff_url_join(char *str, int size, const char *proto, const char *authorization, const char *hostname, int port, const char *fmt,...)
Definition: url.c:36
static int do_llnw_auth(RTMPContext *rt, const char *user, const char *nonce)
Definition: rtmpproto.c:1635
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 ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist)
Create an URLContext for accessing to the resource indicated by url, and open it. ...
Definition: avio.c:336
int flv_off
number of bytes read from current buffer
Definition: rtmpproto.c:93
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:1490
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:556
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:767
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:539
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:1824
#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:2227
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:1694
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:160
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:1375
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:479
#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:2335
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:2578
int stream_id
ID assigned by the server for the stream.
Definition: rtmpproto.c:90
if(ret< 0)
Definition: vf_mcdeint.c:282
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:446
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
static double c[64]
int av_reallocp(void *ptr, size_t size)
Allocate or reallocate a block of memory.
Definition: mem.c:187
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:426
static int rtmp_calc_swfhash(URLContext *s)
Definition: rtmpproto.c:1110
#define rnd()
Definition: checkasm.h:65
char * filename
specified URL
Definition: url.h:43
void av_hmac_free(AVHMAC *c)
Free an AVHMAC context.
Definition: hmac.c:126
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
struct AVMD5 * md5
Definition: movenc-test.c:56
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:416
#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:1896
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:3081
#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:2396
static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
Definition: rtmpproto.c:2035
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:1574
#define RTMP_CLIENT_VER3
Definition: rtmp.h:39
AVDictionary * opts
Definition: movenc-test.c:50
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:2175
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:1523
char * ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase)
Definition: utils.c:4100
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:419
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:2005