1 /*
2 * RTMP network protocol
3 * Copyright (c) 2009 Konstantin Shishkov
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * RTMP protocol
25 */
26
38
40
46
47 #if CONFIG_ZLIB
48 #include <zlib.h>
49 #endif
50
51 #define APP_MAX_LENGTH 1024
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
58 /** RTMP protocol handler state */
63 STATE_PLAYING,
///< client has started receiving multimedia data from server
64 STATE_SEEKING,
///< client has started the seek operation. Back on STATE_PLAYING when the time comes
65 STATE_PUBLISHING,
///< client has started sending multimedia data to server (for output)
70
75
76 /** protocol handler context */
80 RTMPPacket *
prev_pkt[2];
///< packet history used when reading and sending packets ([0] for reading, [1] for writing)
82 int in_chunk_size;
///< size of the chunks incoming RTMP packets are divided into
83 int out_chunk_size;
///< size of the chunks outgoing RTMP packets are divided into
85 char *
playpath;
///< stream identifier to play (with possible "mp4:" prefix)
86 int live;
///< 0: recorded, -1: live, -2: both
87 char *
app;
///< name of application
88 char *
conn;
///< append arbitrary AMF data to the Connect message
90 int stream_id;
///< ID assigned by the server for the stream
93 int flv_off;
///< number of bytes read from current buffer
97 uint32_t
bytes_read;
///< number of bytes read from server
99 int skip_bytes;
///< number of bytes to skip from the input FLV stream in the next write call
103 char*
tcurl;
///< url of the target stream
105 char*
swfhash;
///< SHA256 hash of the decompressed SWF file (32 bytes)
107 int swfsize;
///< size of the decompressed SWF file
109 char*
swfverify;
///< URL to player swf file, compute hash/size automatically
115 int flush_interval;
///< number of packets flushed in the same request (RTMPT only)
116 int encrypted;
///< use an encrypted connection (RTMPE only)
122 int nb_streamid;
///< The next stream id to return on createStream calls
129
130 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
131 /** Client key used for digest signing */
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 ///< length of partial key used for first server digest signing
142 /** Key used for RTMP server digest signing */
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
154 {
155 int err;
156
163 return err;
164 }
165 }
166
172
173 return 0;
174 }
175
177 {
181 }
182
184 char **tracked_method)
185 {
188 double pkt_id;
190 int i;
191
195
198 continue;
199
202 break;
203 }
204
205 return 0;
206 }
207
209 {
210 int i;
211
218 }
219
221 {
223
227 double pkt_id;
229
232 goto fail;
233
235 goto fail;
236
238 goto fail;
239 }
240
243 fail:
246 }
247
249 {
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
273 } else {
274 goto fail;
275 }
276
277 switch (type) {
278 case 'B':
280 break;
281 case 'S':
283 break;
284 case 'N':
286 break;
287 case 'Z':
289 break;
290 case 'O':
291 if (value[0] != '0')
293 else
295 break;
296 default:
297 goto fail;
298 break;
299 }
300
301 return 0;
302
303 fail:
306 }
307
308 /**
309 * Generate 'connect' call and send it to the server.
310 */
312 {
316
320
322
328
332 }
335
339 }
340
348
349 /* Tell the server we support all the audio codecs except
350 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
351 * which are unused in the RTMP protocol implementation. */
358
362 }
363 }
365
367 char *param = rt->
conn;
368
369 // Write arbitrary AMF data to the Connect message.
370 while (param != NULL) {
371 char *sep;
372 param += strspn(param, " ");
373 if (!*param)
374 break;
375 sep = strchr(param, ' ');
376 if (sep)
377 *sep = '0円';
379 // Invalid AMF parameter.
382 }
383
384 if (sep)
385 param = sep + 1;
386 else
387 break;
388 }
389 }
390
392
394 }
395
397 {
403 int stringlen;
404 double seqnum;
407
417 }
418 if (strcmp(command, "connect")) {
422 }
424 if (ret)
426 /* Here one could parse an AMF Object with data as flashVers and others. */
429 "app", tmpstr, sizeof(tmpstr));
430 if (ret)
432 if (!ret && strcmp(tmpstr, rt->
app))
436
437 // Send Window Acknowledgement Size (as defined in speficication)
447 if (ret < 0)
449 // Send Peer Bandwidth
455 bytestream_put_byte(&p, 2); // dynamic
460 if (ret < 0)
462
463 // Ping request
467
469 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
470 bytestream_put_be32(&p, 0);
474 if (ret < 0)
476
477 // Chunk size
481
487 if (ret < 0)
489
490 // Send result_ NetConnection.Connect.Success to connect
495
499
506
517
522 if (ret < 0)
524
537
539 }
540
541 /**
542 * Generate 'releaseStream' call and send it to the server. It should make
543 * the server release some channel for media streams.
544 */
546 {
550
554
561
563 }
564
565 /**
566 * Generate 'FCPublish' call and send it to the server. It should make
567 * the server preapare for receiving media streams.
568 */
570 {
574
578
585
587 }
588
589 /**
590 * Generate 'FCUnpublish' call and send it to the server. It should make
591 * the server destroy stream.
592 */
594 {
598
602
609
611 }
612
613 /**
614 * Generate 'createStream' call and send it to the server. It should make
615 * the server allocate some channel for media streams.
616 */
618 {
622
624
626 0, 25)) < 0)
628
633
635 }
636
637
638 /**
639 * Generate 'deleteStream' call and send it to the server. It should make
640 * the server remove some channel for media streams.
641 */
643 {
647
649
651 0, 34)) < 0)
653
659
661 }
662
663 /**
664 * Generate client buffer time and send it to the server.
665 */
667 {
671
673 1, 10)) < 0)
675
677 bytestream_put_be16(&p, 3);
680
682 }
683
684 /**
685 * Generate 'play' call and send it to the server, then ping the server
686 * to start actual playing.
687 */
689 {
693
695
699
701
708
710 }
711
713 {
717
719 timestamp);
720
723
725
731
733 }
734
735 /**
736 * Generate 'publish' call and send it to the server.
737 */
739 {
743
745
749
751
758
760 }
761
762 /**
763 * Generate ping reply and send it to the server.
764 */
766 {
770
771 if (ppkt->
size < 6) {
775 }
776
780
782 bytestream_put_be16(&p, 7);
784
786 }
787
788 /**
789 * Generate SWF verification message and send it to the server.
790 */
792 {
796
799 0, 44)) < 0)
801
803 bytestream_put_be16(&p, 27);
805
807 }
808
809 /**
810 * Generate server bandwidth message and send it to the server.
811 */
813 {
817
819 0, 4)) < 0)
821
824
826 }
827
828 /**
829 * Generate check bandwidth message and send it to the server.
830 */
832 {
836
838 0, 21)) < 0)
840
845
847 }
848
849 /**
850 * Generate report on bytes read so far and send it to the server.
851 */
853 {
857
859 ts, 4)) < 0)
861
864
866 }
867
869 const char *subscribe)
870 {
874
876 0, 27 + strlen(subscribe))) < 0)
878
884
886 }
887
890 {
893 int i;
894
896 if (!sha)
898
899 if (keylen < 64) {
900 memcpy(hmac_buf, key, keylen);
901 } else {
905 }
906 for (i = 0; i < 64; i++)
908
911 if (gap <= 0) {
913 } else { //skip 32 bytes used for storing digest
916 }
918
919 for (i = 0; i < 64; i++)
924
926
927 return 0;
928 }
929
931 int add_val)
932 {
933 int i, digest_pos = 0;
934
935 for (i = 0; i < 4; i++)
936 digest_pos += buf[i + off];
937 digest_pos = digest_pos % mod_val + add_val;
938
939 return digest_pos;
940 }
941
942 /**
943 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
944 * will be stored) into that packet.
945 *
946 * @param buf handshake data (1536 bytes)
947 * @param encrypted use an encrypted connection (RTMPE)
948 * @return offset to the digest inside input data
949 */
951 {
953
954 if (encrypted)
956 else
958
961 buf + digest_pos);
962 if (ret < 0)
964
965 return digest_pos;
966 }
967
968 /**
969 * Verify that the received server response has the expected digest value.
970 *
971 * @param buf handshake data received from the server (1536 bytes)
972 * @param off position to search digest offset from
973 * @return 0 if digest is valid, digest position otherwise
974 */
976 {
979
981
984 digest);
985 if (ret < 0)
987
988 if (!memcmp(digest, buf + digest_pos, 32))
989 return digest_pos;
990 return 0;
991 }
992
995 {
998
1001 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1003 }
1004
1006 bytestream_put_byte(&p, 1);
1007 bytestream_put_byte(&p, 1);
1008 bytestream_put_be32(&p, rt->
swfsize);
1009 bytestream_put_be32(&p, rt->
swfsize);
1010
1013
1014 return 0;
1015 }
1016
1017 #if CONFIG_ZLIB
1018 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
1019 uint8_t **out_data, int64_t *out_size)
1020 {
1021 z_stream zs = { 0 };
1022 void *ptr;
1025
1026 zs.avail_in = in_size;
1027 zs.next_in = in_data;
1028 ret = inflateInit(&zs);
1029 if (ret != Z_OK)
1031
1032 do {
1034
1035 zs.avail_out = sizeof(tmp_buf);
1036 zs.next_out = tmp_buf;
1037
1038 ret = inflate(&zs, Z_NO_FLUSH);
1039 if (ret != Z_OK && ret != Z_STREAM_END) {
1041 goto fail;
1042 }
1043
1044 size = sizeof(tmp_buf) - zs.avail_out;
1045 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1047 goto fail;
1048 }
1049 *out_data = ptr;
1050
1051 memcpy(*out_data + *out_size, tmp_buf, size);
1053 } while (zs.avail_out == 0);
1054
1055 fail:
1056 inflateEnd(&zs);
1058 }
1059 #endif
1060
1062 {
1064 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1065 int64_t in_size, out_size;
1067 char swfhash[32];
1068 int swfsize;
1069 int ret = 0;
1070
1071 /* Get the SWF player file. */
1075 goto fail;
1076 }
1077
1080 goto fail;
1081 }
1082
1085 goto fail;
1086 }
1087
1089 goto fail;
1090
1091 if (in_size < 3) {
1093 goto fail;
1094 }
1095
1096 if (!memcmp(in_data, "CWS", 3)) {
1097 /* Decompress the SWF player file using Zlib. */
1100 goto fail;
1101 }
1102 *in_data = 'F'; // magic stuff
1103 memcpy(out_data, in_data, 8);
1104 out_size = 8;
1105
1106 #if CONFIG_ZLIB
1107 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1108 &out_data, &out_size)) < 0)
1109 goto fail;
1110 #else
1112 "Zlib is required for decompressing the SWF player file.\n");
1114 goto fail;
1115 #endif
1116 swfsize = out_size;
1117 swfdata = out_data;
1118 } else {
1119 swfsize = in_size;
1120 swfdata = in_data;
1121 }
1122
1123 /* Compute the SHA256 hash of the SWF player file. */
1125 "Genuine Adobe Flash Player 001", 30,
1126 swfhash)) < 0)
1127 goto fail;
1128
1129 /* Set SWFVerification parameters. */
1132
1133 fail:
1138 }
1139
1140 /**
1141 * Perform handshake with the server by means of exchanging pseudorandom data
1142 * signed with HMAC-SHA2 digest.
1143 *
1144 * @return 0 if handshake succeeds, negative value otherwise
1145 */
1147 {
1150 3, // unencrypted data
1151 0, 0, 0, 0, // client uptime
1156 };
1159 int i;
1160 int server_pos, client_pos;
1163
1165
1167 // generate handshake packet - 1536 bytes of pseudorandom data
1170
1171 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1172 /* When the client wants to use RTMPE, we have to change the command
1173 * byte to 0x06 which means to use encrypted data and we have to set
1174 * the flash version to at least 9.0.115.0. */
1175 tosend[0] = 6;
1176 tosend[5] = 128;
1177 tosend[6] = 0;
1178 tosend[7] = 3;
1179 tosend[8] = 2;
1180
1181 /* Initialize the Diffie-Hellmann context and generate the public key
1182 * to send to the server. */
1185 }
1186
1188 if (client_pos < 0)
1189 return client_pos;
1190
1195 }
1196
1201 }
1202
1207 }
1208
1211 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1212
1213 if (rt->
is_input && serverdata[5] >= 3) {
1215 if (server_pos < 0)
1216 return server_pos;
1217
1218 if (!server_pos) {
1219 type = 1;
1221 if (server_pos < 0)
1222 return server_pos;
1223
1224 if (!server_pos) {
1227 }
1228 }
1229
1230 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1231 * key are the last 32 bytes of the server handshake. */
1236 }
1237
1240 digest);
1241 if (ret < 0)
1243
1245 0, digest, 32, signature);
1246 if (ret < 0)
1248
1249 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1250 /* Compute the shared secret key sent by the server and initialize
1251 * the RC4 encryption. */
1253 tosend + 1, type)) < 0)
1255
1256 /* Encrypt the signature received by the server. */
1258 }
1259
1263 }
1264
1269 digest);
1270 if (ret < 0)
1272
1274 digest, 32,
1275 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1276 if (ret < 0)
1278
1279 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1280 /* Encrypt the signature to be send to the server. */
1282 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1283 serverdata[0]);
1284 }
1285
1286 // write reply back to the server
1288 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1290
1291 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1292 /* Set RC4 keys for encryption and update the keystreams. */
1295 }
1296 } else {
1297 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1298 /* Compute the shared secret key sent by the server and initialize
1299 * the RC4 encryption. */
1301 tosend + 1, 1)) < 0)
1303
1304 if (serverdata[0] == 9) {
1305 /* Encrypt the signature received by the server. */
1307 serverdata[0]);
1308 }
1309 }
1310
1314
1315 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1316 /* Set RC4 keys for encryption and update the keystreams. */
1319 }
1320 }
1321
1322 return 0;
1323 }
1324
1326 uint32_t *second_int, char *arraydata,
1327 int size)
1328 {
1329 int inoutsize;
1330
1333 if (inoutsize <= 0)
1337 " not following standard\n", (int)inoutsize);
1339 }
1340
1341 *first_int =
AV_RB32(arraydata);
1342 *second_int =
AV_RB32(arraydata + 4);
1343 return 0;
1344 }
1345
1347 uint32_t second_int, char *arraydata, int size)
1348 {
1349 int inoutsize;
1350
1351 AV_WB32(arraydata, first_int);
1352 AV_WB32(arraydata + 4, second_int);
1358 }
1359
1360 return 0;
1361 }
1362
1363 /**
1364 * rtmp handshake server side
1365 */
1367 {
1369 uint32_t hs_epoch;
1370 uint32_t hs_my_epoch;
1373 uint32_t zeroes;
1375 int randomidx = 0;
1376 int inoutsize = 0;
1378
1380 if (inoutsize <= 0) {
1383 }
1384 // Check Version
1385 if (buffer[0] != 3) {
1388 }
1391 "Unable to write answer - RTMP S0\n");
1393 }
1394 /* Receive C1 */
1397 if (ret) {
1400 }
1401 /* Send S1 */
1402 /* By now same epoch will be sent */
1403 hs_my_epoch = hs_epoch;
1404 /* Generate random */
1406 randomidx += 4)
1408
1411 if (ret) {
1414 }
1415 /* Send S2 */
1418 if (ret) {
1421 }
1422 /* Receive C2 */
1425 if (ret) {
1428 }
1429 if (temp != hs_my_epoch)
1431 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1432 if (memcmp(buffer + 8, hs_s1 + 8,
1435 "Erroneous C2 Message random does not match up\n");
1436
1437 return 0;
1438 }
1439
1441 {
1444
1445 if (pkt->
size < 4) {
1447 "Too short chunk size change packet (%d)\n",
1450 }
1451
1453 /* Send the same chunk size change packet back to the server,
1454 * setting the outgoing chunk size to the same as the incoming one. */
1459 }
1460
1466 }
1469
1470 return 0;
1471 }
1472
1474 {
1477
1478 if (pkt->
size < 2) {
1482 }
1483
1485 if (t == 6) {
1486 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1488 } else if (t == 26) {
1492 } else {
1494 }
1495 }
1496
1497 return 0;
1498 }
1499
1501 {
1503
1504 if (pkt->
size < 4) {
1506 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1509 }
1510
1516
1517 }
1520
1521 return 0;
1522 }
1523
1525 {
1527
1528 if (pkt->
size < 4) {
1530 "Too short server bandwidth report packet (%d)\n",
1533 }
1534
1540 }
1542
1543 return 0;
1544 }
1545
1547 const char *opaque, const char *challenge)
1548 {
1552 if (!md5)
1554
1556
1563 sizeof(hash));
1566 if (opaque)
1568 else if (challenge)
1573 sizeof(hash));
1575 "?authmod=%s&user=%s&challenge=%s&response=%s",
1576 "adobe", user, challenge2, hashstr);
1577 if (opaque)
1579 "&opaque=%s", opaque);
1580
1582 return 0;
1583 }
1584
1586 {
1588 char hashstr1[33], hashstr2[33];
1589 const char *realm = "live";
1590 const char *method = "publish";
1591 const char *qop = "auth";
1592 const char *nc = "00000001";
1593 char cnonce[10];
1595 if (!md5)
1597
1599
1608 hashstr1[32] = '0円';
1609
1614 if (!strchr(rt->
app,
'/'))
1618 hashstr2[32] = '0円';
1619
1623 if (nonce)
1635
1637 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1638 "llnw", user, nonce, cnonce, nc, hashstr1);
1639
1641 return 0;
1642 }
1643
1645 {
1647 char buf[300], *ptr, authmod[15];
1648 int i = 0, ret = 0;
1649 const char *user = "", *salt = "", *opaque = NULL,
1650 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1651
1652 if (!(cptr = strstr(desc, "authmod=adobe")) &&
1653 !(cptr = strstr(desc, "authmod=llnw"))) {
1655 "Unknown connect error (unsupported authentication method?)\n");
1657 }
1658 cptr += strlen("authmod=");
1659 while (*cptr && *cptr != ' ' && i < sizeof(authmod) - 1)
1660 authmod[i++] = *cptr++;
1661 authmod[i] = '0円';
1662
1666 }
1667
1668 if (strstr(desc, "?reason=authfailed")) {
1671 } else if (strstr(desc, "?reason=nosuchuser")) {
1674 }
1675
1679 }
1680
1682
1683 if (strstr(desc, "code=403 need auth")) {
1685 "?authmod=%s&user=%s", authmod, rt->
username);
1686 return 0;
1687 }
1688
1689 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1692 }
1693
1696
1697 while (ptr) {
1698 char *next = strchr(ptr, '&');
1699 char *
value = strchr(ptr,
'=');
1700 if (next)
1701 *next++ = '0円';
1702 if (value)
1703 *value++ = '0円';
1704 if (!strcmp(ptr, "user")) {
1706 } else if (!strcmp(ptr, "salt")) {
1708 } else if (!strcmp(ptr, "opaque")) {
1710 } else if (!strcmp(ptr, "challenge")) {
1712 } else if (!strcmp(ptr, "nonce")) {
1714 }
1715 ptr = next;
1716 }
1717
1718 if (!strcmp(authmod, "adobe")) {
1719 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1721 } else {
1724 }
1725
1727 return 0;
1728 }
1729
1731 {
1734 char *tracked_method = NULL;
1738
1741
1743 "description", tmpstr, sizeof(tmpstr))) {
1744 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1745 !strcmp(tracked_method, "releaseStream") ||
1746 !strcmp(tracked_method, "FCSubscribe") ||
1747 !strcmp(tracked_method, "FCPublish"))) {
1748 /* Gracefully ignore Adobe-specific historical artifact errors. */
1750 ret = 0;
1751 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1753 if (!ret) {
1756 }
1757 } else
1759 av_log(s, level,
"Server error: %s\n", tmpstr);
1760 }
1761
1764 }
1765
1767 {
1772
1773 // Send Stream Begin 1
1778 }
1779
1781 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1783
1786
1788
1790 }
1791
1793 const char *status, const char *filename)
1794 {
1797 char statusmsg[128];
1800
1806 }
1807
1813
1820 snprintf(statusmsg,
sizeof(statusmsg),
1821 "%s is now published", filename);
1829
1834
1836 }
1837
1839 {
1841 double seqnum;
1842 char filename[64];
1844 int stringlen;
1845 char *pchar;
1851
1854 &stringlen)) {
1857 }
1858
1860 if (ret)
1863 if (ret)
1865 if (!strcmp(command, "FCPublish") ||
1866 !strcmp(command, "publish")) {
1868 sizeof(filename), &stringlen);
1869 // check with url
1872 if (!pchar) {
1874 "Unable to find / in url %s, bad format\n",
1877 }
1878 pchar++;
1879 if (strcmp(pchar, filename))
1881 " %s\n", filename, pchar);
1882 }
1884 }
1885
1886 if (!strcmp(command, "FCPublish")) {
1892 }
1895 } else if (!strcmp(command, "publish")) {
1897 if (ret < 0)
1899
1900 // Send onStatus(NetStream.Publish.Start)
1902 filename);
1903 } else if (!strcmp(command, "play")) {
1905 if (ret < 0)
1909 filename);
1910 } else {
1916 }
1921 if (!strcmp(command, "createStream")) {
1924 rt->
nb_streamid++;
/* Values 0 and 2 are reserved */
1926 /* By now we don't control which streams are removed in
1927 * deleteStream. There is no stream creation control
1928 * if a client creates more than 2^32 - 2 streams. */
1929 }
1930 }
1936 }
1937
1939 {
1941 char *tracked_method = NULL;
1942 int ret = 0;
1943
1946
1947 if (!tracked_method) {
1948 /* Ignore this reply when the current method is not tracked. */
1950 }
1951
1952 if (!strcmp(tracked_method, "connect")) {
1955 goto fail;
1956
1958 goto fail;
1959 } else {
1961 goto fail;
1962 }
1963
1965 goto fail;
1966
1968 /* Send the FCSubscribe command when the name of live
1969 * stream is defined by the user or if it's a live stream. */
1972 goto fail;
1973 }
else if (rt->
live == -1) {
1975 goto fail;
1976 }
1977 }
1978 } else if (!strcmp(tracked_method, "createStream")) {
1979 //extract a number from the result
1980 if (pkt->
data[10] || pkt->
data[19] != 5 || pkt->
data[20]) {
1982 } else {
1984 }
1985
1988 goto fail;
1989 } else {
1991 goto fail;
1993 goto fail;
1994 }
1995 }
1996
1997 fail:
2000 }
2001
2003 {
2009
2010 for (i = 0; i < 2; i++) {
2012 if (t < 0)
2013 return 1;
2015 }
2016
2018 if (!t && !strcmp(tmpstr, "error")) {
2020 "description", tmpstr, sizeof(tmpstr));
2021 if (t || !tmpstr[0])
2023 tmpstr, sizeof(tmpstr));
2024 if (!t)
2026 return -1;
2027 }
2028
2032 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
2035
2036 return 0;
2037 }
2038
2040 {
2042 int ret = 0;
2043
2044 //TODO: check for the messages sent for wrong state?
2065 }
2066
2068 }
2069
2071 {
2072 int old_flv_size;
2073
2074 // generate packet header and put data into buffer for FLV demuxer
2076 // There is old unread data in the buffer, thus append at the end
2079 } else {
2080 // All data has been read, write the new data at the start of the buffer
2081 old_flv_size = 0;
2084 }
2085
2086 return old_flv_size;
2087 }
2088
2090 {
2091 int old_flv_size,
ret;
2094 const int size = pkt->
size - skip;
2096
2098
2102 }
2105 bytestream2_put_byte(&pbc, pkt->
type);
2106 bytestream2_put_be24(&pbc, size);
2107 bytestream2_put_be24(&pbc, ts);
2108 bytestream2_put_byte(&pbc, ts >> 24);
2109 bytestream2_put_be24(&pbc, 0);
2111 bytestream2_put_be32(&pbc, 0);
2112
2113 return 0;
2114 }
2115
2117 {
2120 char statusmsg[128];
2121 int stringlen,
ret, skip = 0;
2123
2126 &stringlen))
2128
2129 // Skip the @setDataFrame string and validate it is a notification
2130 if (!strcmp(commandbuffer, "@setDataFrame")) {
2133 sizeof(statusmsg), &stringlen);
2134 if (ret < 0)
2136 }
2137
2139 }
2140
2141 /**
2142 * Parse received packet and possibly perform some action depending on
2143 * the packet contents.
2144 * @return 0 for no errors, negative values for serious errors which prevent
2145 * further communications, positive values for uncritical errors
2146 */
2148 {
2150
2151 #ifdef DEBUG
2153 #endif
2154
2155 switch (pkt->
type) {
2157 av_dlog(s,
"received bytes read report\n");
2158 break;
2162 break;
2166 break;
2170 break;
2174 break;
2178 break;
2183 /* Audio, Video and Metadata packets are parsed in get_packet() */
2184 break;
2185 default:
2187 break;
2188 }
2189 return 0;
2190 }
2191
2193 {
2198 uint32_t ts, cts, pts = 0;
2199
2201
2205 }
2206
2209
2210 /* copy data while rewriting timestamps */
2212
2214 type = bytestream_get_byte(&next);
2215 size = bytestream_get_be24(&next);
2216 cts = bytestream_get_be24(&next);
2217 cts |= bytestream_get_byte(&next) << 24;
2218 if (!pts)
2219 pts = cts;
2220 ts += cts - pts;
2221 pts = cts;
2222 if (size + 3 + 4 > pkt->
data + pkt->
size - next)
2223 break;
2224 bytestream_put_byte(&p, type);
2225 bytestream_put_be24(&p, size);
2226 bytestream_put_be24(&p, ts);
2227 bytestream_put_byte(&p, ts >> 24);
2228 memcpy(p, next, size + 3 + 4);
2229 next += size + 3 + 4;
2230 p += size + 3 + 4;
2231 }
2234 "RTMP_PT_METADATA packet\n");
2236 }
2237
2238 return 0;
2239 }
2240
2241 /**
2242 * Interact with the server by receiving and sending RTMP packets until
2243 * there is some significant data (media data or expected status notification).
2244 *
2245 * @param s reading context
2246 * @param for_header non-zero value tells function to work until it
2247 * gets notification from the server that playing has been started,
2248 * otherwise function will work until some media data is received (or
2249 * an error happens)
2250 * @return 0 for successful operation, negative value in case of error
2251 */
2253 {
2256
2259
2260 for (;;) {
2265 if (ret == 0) {
2267 } else {
2269 }
2270 }
2277 }
2278
2280
2281 // At this point we must check if we are in the seek state and continue
2282 // with the next packet. handle_invoke will get us out of this state
2283 // when the right message is encountered
2286 // We continue, let the natural flow of things happen:
2287 // AVERROR(EAGAIN) or handle_invoke gets us out of here
2288 continue;
2289 }
2290
2291 if (ret < 0) {//serious error in current packet
2294 }
2297 return 0;
2298 }
2302 }
2308 return 0;
2309 }
2312 continue;
2313 }
2325 return 0;
2326 }
2328 }
2329 }
2330
2332 {
2334 int ret = 0, i, j;
2335
2342 }
2345 for (i = 0; i < 2; i++) {
2349 }
2350
2355 }
2356
2357 /**
2358 * Open RTMP connection and verify that the stream can be played.
2359 *
2360 * URL syntax: rtmp://server[:port][/app][/playpath]
2361 * where 'app' is first one or two directories in the path
2362 * (e.g. /ondemand/, /flash/live/, etc.)
2363 * and 'playpath' is a file name (the rest of the path,
2364 * may be prefixed with "mp4:")
2365 */
2367 {
2369 char proto[8], hostname[256], path[1024], auth[100], *fname;
2370 char *old_app;
2372 int port;
2375
2378
2380
2382 hostname, sizeof(hostname), &port,
2384
2385 if (strchr(path, ' ')) {
2387 "Detected librtmp style URL parameters, these aren't supported "
2388 "by the libavformat internal RTMP handler currently enabled. "
2389 "See the documentation for the correct way to pass parameters.\n");
2390 }
2391
2392 if (auth[0]) {
2393 char *ptr = strchr(auth, ':');
2394 if (ptr) {
2395 *ptr = '0円';
2398 }
2399 }
2400
2401 if (rt->
listen && strcmp(proto,
"rtmp")) {
2403 proto);
2405 }
2406 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2407 if (!strcmp(proto, "rtmpts"))
2409
2410 /* open the http tunneling connection */
2411 ff_url_join(buf,
sizeof(buf),
"ffrtmphttp", NULL, hostname, port, NULL);
2412 } else if (!strcmp(proto, "rtmps")) {
2413 /* open the tls connection */
2414 if (port < 0)
2416 ff_url_join(buf,
sizeof(buf),
"tls", NULL, hostname, port, NULL);
2417 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2418 if (!strcmp(proto, "rtmpte"))
2419 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2420
2421 /* open the encrypted connection */
2422 ff_url_join(buf,
sizeof(buf),
"ffrtmpcrypt", NULL, hostname, port, NULL);
2424 } else {
2425 /* open the tcp connection */
2426 if (port < 0)
2429 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port,
2430 "?listen&listen_timeout=%d",
2432 else
2433 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port, NULL);
2434 }
2435
2436 reconnect:
2440 goto fail;
2441 }
2442
2445 goto fail;
2446 }
2447
2450 goto fail;
2452 goto fail;
2453
2457
2458 // Keep the application name when it has been defined by the user.
2460
2464 goto fail;
2465 }
2466
2467 //extract "app" part from path
2468 if (!strncmp(path, "/ondemand/", 10)) {
2469 fname = path + 10;
2470 memcpy(rt->
app,
"ondemand", 9);
2471 } else {
2472 char *next = *path ? path + 1 : path;
2473 char *p = strchr(next, '/');
2474 if (!p) {
2475 fname = next;
2477 } else {
2478 // make sure we do not mismatch a playpath for an application instance
2479 char *
c = strchr(p + 1,
':');
2480 fname = strchr(p + 1, '/');
2481 if (!fname || (c && c < fname)) {
2482 fname = p + 1;
2484 } else {
2485 fname++;
2487 }
2488 }
2489 }
2490
2491 if (old_app) {
2492 // The name of application has been defined by the user, override it.
2495 goto fail;
2496 }
2499 }
2500
2502 int len = strlen(fname);
2503
2507 goto fail;
2508 }
2509
2510 if (!strchr(fname, ':') && len >= 4 &&
2511 (!strcmp(fname + len - 4, ".f4v") ||
2512 !strcmp(fname + len - 4, ".mp4"))) {
2514 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
2515 fname[len - 4] = '0円';
2516 } else {
2518 }
2520 }
2521
2526 goto fail;
2527 }
2529 port,
"/%s", rt->
app);
2530 }
2531
2536 goto fail;
2537 }
2542 } else {
2545 }
2546 }
2547
2552
2557 goto fail;
2558 } else {
2560 goto fail;
2561 }
2562
2563 do {
2565 }
while (ret ==
AVERROR(EAGAIN));
2566 if (ret < 0)
2567 goto fail;
2568
2570 int i;
2575 for (i = 0; i < 2; i++)
2579 goto reconnect;
2580 }
2581
2583 int err;
2584 // generate FLV header for demuxer
2587 return err;
2590 } else {
2595 }
2596
2599 return 0;
2600
2601 fail:
2605 }
2606
2608 {
2610 int orig_size =
size;
2612
2613 while (size > 0) {
2615
2616 if (data_left >= size) {
2619 return orig_size;
2620 }
2621 if (data_left > 0) {
2623 buf += data_left;
2624 size -= data_left;
2626 return data_left;
2627 }
2630 }
2631 return orig_size;
2632 }
2633
2636 {
2640 "Seek on stream index %d at timestamp %"PRId64" with flags %08x\n",
2641 stream_index, timestamp, flags);
2642 if ((ret =
gen_seek(s, rt, timestamp)) < 0) {
2644 "Unable to send seek command on stream index %d at timestamp "
2645 "%"PRId64" with flags %08x\n",
2646 stream_index, timestamp, flags);
2648 }
2651 return timestamp;
2652 }
2653
2655 {
2657 int size_temp =
size;
2658 int pktsize, pkttype;
2659 uint32_t ts;
2663
2664 do {
2667 buf_temp += skip;
2668 size_temp -= skip;
2670 continue;
2671 }
2672
2681 break;
2682
2683 pkttype = bytestream_get_byte(&header);
2684 pktsize = bytestream_get_be24(&header);
2685 ts = bytestream_get_be24(&header);
2686 ts |= bytestream_get_byte(&header) << 24;
2687 bytestream_get_be24(&header);
2689
2692
2693 //force 12bytes header
2697 pktsize += 16;
2700 channel)) < 0)
2703 }
2704
2705 //this can be a big packet, it's better to send it right here
2707 pkttype, ts, pktsize)) < 0)
2709
2712
2715 }
2716
2720 size_temp = 0;
2721 } else {
2725 }
2726
2729
2736 }
2737 } while (buf_temp - buf < size);
2738
2742
2743 /* set stream into nonblocking mode */
2745
2746 /* try to read one byte from the stream */
2748
2749 /* switch the stream back into blocking mode */
2751
2753 /* no incoming data to handle */
2755 } else if (ret < 0) {
2757 } else if (ret == 1) {
2759
2765
2768
2770 }
2771
2773 }
2774
2775 #define OFFSET(x) offsetof(RTMPContext, x)
2776 #define DEC AV_OPT_FLAG_DECODING_PARAM
2777 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2778
2781 {
"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},
2783 {
"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},
2784 {
"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},
2785 {
"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"},
2789 {
"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},
2791 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2793 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
2795 {
"rtmp_swfverify",
"URL to player swf file, compute hash/size automatically.",
OFFSET(swfverify),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2796 {
"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},
2797 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2798 {
"listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2799 {
"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" },
2800 { NULL },
2801 };
2802
2803 #define RTMP_PROTOCOL(flavor) \
2804 static const AVClass flavor##_class = { \
2805 .class_name = #flavor, \
2806 .item_name = av_default_item_name, \
2807 .option = rtmp_options, \
2808 .version = LIBAVUTIL_VERSION_INT, \
2809 }; \
2810 \
2811 URLProtocol ff_##flavor##_protocol = { \
2812 .name = #flavor, \
2813 .url_open = rtmp_open, \
2814 .url_read = rtmp_read, \
2815 .url_read_seek = rtmp_seek, \
2816 .url_write = rtmp_write, \
2817 .url_close = rtmp_close, \
2818 .priv_data_size = sizeof(RTMPContext), \
2819 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2820 .priv_data_class= &flavor##_class, \
2821 };
2822
2823