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