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