53 #define APP_MAX_LENGTH 1024
54 #define PLAYPATH_MAX_LENGTH 256
55 #define TCURL_MAX_LENGTH 512
56 #define FLASHVER_MAX_LENGTH 64
57 #define RTMP_PKTDATA_DEFAULT_SIZE 4096
128 #define PLAYER_KEY_OPEN_PART_LEN 30
131 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
132 'F',
'l',
'a',
's',
'h',
' ',
'P',
'l',
'a',
'y',
'e',
'r',
' ',
'0',
'0',
'1',
134 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
135 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
136 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
139 #define SERVER_KEY_OPEN_PART_LEN 36
142 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
143 'F',
'l',
'a',
's',
'h',
' ',
'M',
'e',
'd',
'i',
'a',
' ',
144 'S',
'e',
'r',
'v',
'e',
'r',
' ',
'0',
'0',
'1',
146 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
147 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
148 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
181 char **tracked_method)
257 if (param[0] && param[1] ==
':') {
260 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
263 value = strchr(field,
':');
364 char *param = rt->
conn;
367 while (param !=
NULL) {
369 param += strspn(param,
" ");
372 sep = strchr(param,
' ');
415 if (strcmp(command,
"connect")) {
426 "app", tmpstr,
sizeof(tmpstr));
429 if (!ret && strcmp(tmpstr, rt->
app))
452 bytestream_put_byte(&p, 2);
466 bytestream_put_be16(&p, 0);
467 bytestream_put_be32(&p, 0);
674 bytestream_put_be16(&p, 3);
756 bytestream_put_be16(&p, 7);
777 bytestream_put_be16(&p, 27);
843 const char *subscribe)
850 0, 27 + strlen(subscribe))) < 0)
874 memcpy(hmac_buf, key, keylen);
880 for (i = 0; i < 64; i++)
893 for (i = 0; i < 64; i++)
907 int i, digest_pos = 0;
909 for (i = 0; i < 4; i++)
910 digest_pos += buf[i + off];
911 digest_pos = digest_pos % mod_val + add_val;
962 if (!memcmp(digest, buf + digest_pos, 32))
975 "Hash of the decompressed SWF file is not 32 bytes long.\n");
980 bytestream_put_byte(&p, 1);
981 bytestream_put_byte(&p, 1);
982 bytestream_put_be32(&p, rt->
swfsize);
983 bytestream_put_be32(&p, rt->
swfsize);
992 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
993 uint8_t **out_data, int64_t *out_size)
1000 zs.avail_in = in_size;
1001 zs.next_in = in_data;
1002 ret = inflateInit(&zs);
1009 zs.avail_out =
sizeof(tmp_buf);
1010 zs.next_out = tmp_buf;
1012 ret = inflate(&zs, Z_NO_FLUSH);
1013 if (ret != Z_OK && ret != Z_STREAM_END) {
1018 size =
sizeof(tmp_buf) - zs.avail_out;
1019 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1025 memcpy(*out_data + *out_size, tmp_buf, size);
1027 }
while (zs.avail_out == 0);
1039 int64_t in_size, out_size;
1070 if (!memcmp(in_data,
"CWS", 3)) {
1077 memcpy(out_data, in_data, 8);
1081 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1082 &out_data, &out_size)) < 0)
1086 "Zlib is required for decompressing the SWF player file.\n");
1099 "Genuine Adobe Flash Player 001", 30,
1134 int server_pos, client_pos;
1145 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1185 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1187 if (rt->
is_input && serverdata[5] >= 3) {
1219 0, digest, 32, signature);
1223 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1227 tosend + 1, type)) < 0)
1249 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1253 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1256 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1262 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1265 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1271 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1275 tosend + 1, 1)) < 0)
1278 if (serverdata[0] == 9) {
1289 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1300 uint32_t *second_int,
char *arraydata,
1311 " not following standard\n", (
int)inoutsize);
1315 *first_int =
AV_RB32(arraydata);
1316 *second_int =
AV_RB32(arraydata + 4);
1321 uint32_t second_int,
char *arraydata,
int size)
1325 AV_WB32(arraydata, first_int);
1326 AV_WB32(arraydata + 4, first_int);
1344 uint32_t hs_my_epoch;
1354 if (inoutsize <= 0) {
1359 if (buffer[0] != 3) {
1365 "Unable to write answer - RTMP S0\n");
1379 hs_my_epoch = hs_epoch;
1405 if (temp != hs_my_epoch)
1407 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1408 if (memcmp(buffer + 8, hs_s1 + 8,
1411 "Erroneous C2 Message random does not match up\n");
1423 "Too short chunk size change packet (%d)\n",
1462 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1464 }
else if (t == 26) {
1482 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1506 "Too short server bandwidth report packet (%d)\n",
1523 const char *opaque,
const char *challenge)
1551 "?authmod=%s&user=%s&challenge=%s&response=%s",
1552 "adobe", user, challenge2, hashstr);
1555 "&opaque=%s", opaque);
1564 char hashstr1[33], hashstr2[33];
1565 const char *realm =
"live";
1566 const char *method =
"publish";
1567 const char *qop =
"auth";
1568 const char *nc =
"00000001";
1584 hashstr1[32] =
'\0';
1592 hashstr2[32] =
'\0';
1611 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1612 "llnw", user, nonce, cnonce, nc, hashstr1);
1621 char buf[300], *ptr, authmod[15];
1623 const char *user =
"", *salt =
"", *opaque =
NULL,
1626 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1627 !(cptr = strstr(desc,
"authmod=llnw"))) {
1629 "Unknown connect error (unsupported authentication method?)\n");
1632 cptr += strlen(
"authmod=");
1633 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1634 authmod[i++] = *cptr++;
1642 if (strstr(desc,
"?reason=authfailed")) {
1645 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1657 if (strstr(desc,
"code=403 need auth")) {
1659 "?authmod=%s&user=%s", authmod, rt->
username);
1663 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1672 char *next = strchr(ptr,
'&');
1673 char *
value = strchr(ptr,
'=');
1678 if (!strcmp(ptr,
"user")) {
1680 }
else if (!strcmp(ptr,
"salt")) {
1682 }
else if (!strcmp(ptr,
"opaque")) {
1684 }
else if (!strcmp(ptr,
"challenge")) {
1686 }
else if (!strcmp(ptr,
"nonce")) {
1692 if (!strcmp(authmod,
"adobe")) {
1693 if ((ret =
do_adobe_auth(rt, user, salt, challenge, opaque)) < 0)
1708 char *tracked_method =
NULL;
1717 "description", tmpstr,
sizeof(tmpstr))) {
1718 if (tracked_method && (!strcmp(tracked_method,
"_checkbw") ||
1719 !strcmp(tracked_method,
"releaseStream") ||
1720 !strcmp(tracked_method,
"FCSubscribe") ||
1721 !strcmp(tracked_method,
"FCPublish"))) {
1725 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1733 av_log(s, level,
"Server error: %s\n", tmpstr);
1746 char statusmsg[128];
1768 if (!strcmp(command,
"FCPublish") ||
1769 !strcmp(command,
"publish")) {
1771 sizeof(filename), &stringlen);
1777 "Unable to find / in url %s, bad format\n",
1782 if (strcmp(pchar, filename))
1784 " %s\n", filename, pchar);
1789 if (!strcmp(command,
"FCPublish")) {
1798 }
else if (!strcmp(command,
"publish")) {
1808 bytestream2_put_be16(&pbc, 0);
1835 snprintf(statusmsg,
sizeof(statusmsg),
1836 "%s is now published", filename);
1856 if (!strcmp(command,
"createStream")) {
1876 char *tracked_method =
NULL;
1882 if (!tracked_method) {
1887 if (!memcmp(tracked_method,
"connect", 7)) {
1908 }
else if (rt->
live == -1) {
1913 }
else if (!memcmp(tracked_method,
"createStream", 12)) {
1915 if (pkt->
data[10] || pkt->
data[19] != 5 || pkt->
data[20]) {
1945 for (i = 0; i < 2; i++) {
1953 if (!t && !strcmp(tmpstr,
"error")) {
1955 "description", tmpstr,
sizeof(tmpstr)))
1963 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
1975 if (!memcmp(pkt->
data,
"\002\000\006_error", 9)) {
1978 }
else if (!memcmp(pkt->
data,
"\002\000\007_result", 10)) {
1981 }
else if (!memcmp(pkt->
data,
"\002\000\010onStatus", 11)) {
1984 }
else if (!memcmp(pkt->
data,
"\002\000\010onBWDone", 11)) {
1987 }
else if (!memcmp(pkt->
data,
"\002\000\015releaseStream", 16) ||
1988 !memcmp(pkt->
data,
"\002\000\011FCPublish", 12) ||
1989 !memcmp(pkt->
data,
"\002\000\007publish", 10) ||
1990 !memcmp(pkt->
data,
"\002\000\010_checkbw", 11) ||
1991 !memcmp(pkt->
data,
"\002\000\014createStream", 15)) {
2004 char statusmsg[128];
2011 unsigned datatowritelength;
2018 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2019 datatowrite = gbc.
buffer;
2022 sizeof(statusmsg), &stringlen))
2024 if (strcmp(statusmsg,
"onMetaData")) {
2036 rt->
flv_size += datatowritelength + 15;
2039 rt->
flv_size = datatowritelength + 15;
2049 bytestream2_put_byte(&pbc, pkt->
type);
2050 bytestream2_put_be24(&pbc, datatowritelength);
2051 bytestream2_put_be24(&pbc, ts);
2052 bytestream2_put_byte(&pbc, ts >> 24);
2053 bytestream2_put_be24(&pbc, 0);
2055 bytestream2_put_be32(&pbc, 0);
2074 switch (pkt->
type) {
2076 av_dlog(s,
"received bytes read report\n");
2129 uint32_t ts, cts, pts=0;
2183 bytestream_put_byte(&p, rpkt.
type);
2184 bytestream_put_be24(&p, rpkt.
data_size);
2185 bytestream_put_be24(&p, ts);
2186 bytestream_put_byte(&p, ts >> 24);
2187 bytestream_put_be24(&p, 0);
2189 bytestream_put_be32(&p, 0);
2210 data_size = bytestream_get_be24(&next);
2212 cts = bytestream_get_be24(&next);
2213 cts |= bytestream_get_byte(&next) << 24;
2218 bytestream_put_be24(&p, ts);
2219 bytestream_put_byte(&p, ts >> 24);
2220 next += data_size + 3 + 4;
2263 char proto[8], hostname[256], path[1024], auth[100], *fname;
2276 hostname,
sizeof(hostname), &port,
2280 char *ptr = strchr(auth,
':');
2288 if (rt->
listen && strcmp(proto,
"rtmp")) {
2293 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2294 if (!strcmp(proto,
"rtmpts"))
2299 }
else if (!strcmp(proto,
"rtmps")) {
2304 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2305 if (!strcmp(proto,
"rtmpte"))
2306 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2317 "?listen&listen_timeout=%d",
2355 if (!strncmp(path,
"/ondemand/", 10)) {
2357 memcpy(rt->
app,
"ondemand", 9);
2359 char *next = *path ? path + 1 : path;
2360 char *p = strchr(next,
'/');
2366 char *
c = strchr(p + 1,
':');
2367 fname = strchr(p + 1,
'/');
2368 if (!fname || (c && c < fname)) {
2389 int len = strlen(fname);
2397 if (!strchr(fname,
':') && len >= 4 &&
2398 (!strcmp(fname + len - 4,
".f4v") ||
2399 !strcmp(fname + len - 4,
".mp4"))) {
2401 }
else if (len >= 4 && !strcmp(fname + len - 4,
".flv")) {
2402 fname[len - 4] =
'\0';
2416 port,
"/%s", rt->
app);
2453 }
while (ret == EAGAIN);
2493 int orig_size =
size;
2499 if (data_left >= size) {
2504 if (data_left > 0) {
2520 int size_temp =
size;
2521 int pktsize, pkttype;
2523 const uint8_t *buf_temp = buf;
2545 pkttype = bytestream_get_byte(&header);
2546 pktsize = bytestream_get_be24(&header);
2547 ts = bytestream_get_be24(&header);
2548 ts |= bytestream_get_byte(&header) << 24;
2549 bytestream_get_be24(&header);
2562 pkttype, ts, pktsize)) < 0)
2592 }
while (buf_temp - buf < size);
2610 }
else if (ret < 0) {
2612 }
else if (ret == 1) {
2629 #define OFFSET(x) offsetof(RTMPContext, x)
2630 #define DEC AV_OPT_FLAG_DECODING_PARAM
2631 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2635 {
"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},
2638 {
"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},
2639 {
"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"},
2643 {
"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},
2645 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str =
NULL }, 0, 0,
DEC},
2647 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
2651 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2652 {
"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" },
2656 #define RTMP_PROTOCOL(flavor) \
2657 static const AVClass flavor##_class = { \
2658 .class_name = #flavor, \
2659 .item_name = av_default_item_name, \
2660 .option = rtmp_options, \
2661 .version = LIBAVUTIL_VERSION_INT, \
2664 URLProtocol ff_##flavor##_protocol = { \
2666 .url_open = rtmp_open, \
2667 .url_read = rtmp_read, \
2668 .url_write = rtmp_write, \
2669 .url_close = rtmp_close, \
2670 .priv_data_size = sizeof(RTMPContext), \
2671 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2672 .priv_data_class= &flavor##_class, \