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
126 #define PLAYER_KEY_OPEN_PART_LEN 30
129 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
130 'F',
'l',
'a',
's',
'h',
' ',
'P',
'l',
'a',
'y',
'e',
'r',
' ',
'0',
'0',
'1',
132 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
133 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
134 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
137 #define SERVER_KEY_OPEN_PART_LEN 36
140 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
141 'F',
'l',
'a',
's',
'h',
' ',
'M',
'e',
'd',
'i',
'a',
' ',
142 'S',
'e',
'r',
'v',
'e',
'r',
' ',
'0',
'0',
'1',
144 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
145 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
146 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
179 char **tracked_method)
255 if (param[0] && param[1] ==
':') {
258 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
261 value = strchr(field,
':');
362 char *param = rt->
conn;
365 while (param != NULL) {
367 param += strspn(param,
" ");
370 sep = strchr(param,
' ');
413 if (strcmp(command,
"connect")) {
424 "app", tmpstr,
sizeof(tmpstr));
427 if (!ret && strcmp(tmpstr, rt->
app))
450 bytestream_put_byte(&p, 2);
464 bytestream_put_be16(&p, 0);
465 bytestream_put_be32(&p, 0);
672 bytestream_put_be16(&p, 3);
754 bytestream_put_be16(&p, 7);
775 bytestream_put_be16(&p, 27);
841 const char *subscribe)
848 0, 27 + strlen(subscribe))) < 0)
872 memcpy(hmac_buf, key, keylen);
878 for (i = 0; i < 64; i++)
891 for (i = 0; i < 64; i++)
905 int i, digest_pos = 0;
907 for (i = 0; i < 4; i++)
908 digest_pos += buf[i + off];
909 digest_pos = digest_pos % mod_val + add_val;
960 if (!memcmp(digest, buf + digest_pos, 32))
973 "Hash of the decompressed SWF file is not 32 bytes long.\n");
978 bytestream_put_byte(&p, 1);
979 bytestream_put_byte(&p, 1);
980 bytestream_put_be32(&p, rt->
swfsize);
981 bytestream_put_be32(&p, rt->
swfsize);
990 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
991 uint8_t **out_data, int64_t *out_size)
998 zs.avail_in = in_size;
999 zs.next_in = in_data;
1000 ret = inflateInit(&zs);
1007 zs.avail_out =
sizeof(tmp_buf);
1008 zs.next_out = tmp_buf;
1010 ret = inflate(&zs, Z_NO_FLUSH);
1011 if (ret != Z_OK && ret != Z_STREAM_END) {
1016 size =
sizeof(tmp_buf) - zs.avail_out;
1017 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1023 memcpy(*out_data + *out_size, tmp_buf, size);
1025 }
while (zs.avail_out == 0);
1036 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1037 int64_t in_size, out_size;
1068 if (!memcmp(in_data,
"CWS", 3)) {
1075 memcpy(out_data, in_data, 8);
1079 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1080 &out_data, &out_size)) < 0)
1084 "Zlib is required for decompressing the SWF player file.\n");
1097 "Genuine Adobe Flash Player 001", 30,
1132 int server_pos, client_pos;
1143 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1183 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1185 if (rt->
is_input && serverdata[5] >= 3) {
1217 0, digest, 32, signature);
1221 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1225 tosend + 1, type)) < 0)
1247 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1251 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1254 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1260 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1263 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1269 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1273 tosend + 1, 1)) < 0)
1276 if (serverdata[0] == 9) {
1287 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1298 uint32_t *second_int,
char *arraydata,
1309 " not following standard\n", (
int)inoutsize);
1313 *first_int =
AV_RB32(arraydata);
1314 *second_int =
AV_RB32(arraydata + 4);
1319 uint32_t second_int,
char *arraydata,
int size)
1323 AV_WB32(arraydata, first_int);
1324 AV_WB32(arraydata + 4, first_int);
1342 uint32_t hs_my_epoch;
1352 if (inoutsize <= 0) {
1357 if (buffer[0] != 3) {
1363 "Unable to write answer - RTMP S0\n");
1377 hs_my_epoch = hs_epoch;
1403 if (temp != hs_my_epoch)
1405 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1406 if (memcmp(buffer + 8, hs_s1 + 8,
1409 "Erroneous C2 Message random does not match up\n");
1421 "Too short chunk size change packet (%d)\n",
1460 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1462 }
else if (t == 26) {
1480 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1504 "Too short server bandwidth report packet (%d)\n",
1521 const char *opaque,
const char *challenge)
1549 "?authmod=%s&user=%s&challenge=%s&response=%s",
1550 "adobe", user, challenge2, hashstr);
1553 "&opaque=%s", opaque);
1562 char hashstr1[33], hashstr2[33];
1563 const char *realm =
"live";
1564 const char *method =
"publish";
1565 const char *qop =
"auth";
1566 const char *nc =
"00000001";
1582 hashstr1[32] =
'\0';
1590 hashstr2[32] =
'\0';
1609 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1610 "llnw", user, nonce, cnonce, nc, hashstr1);
1619 char buf[300], *ptr, authmod[15];
1621 const char *user =
"", *salt =
"", *opaque = NULL,
1622 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1624 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1625 !(cptr = strstr(desc,
"authmod=llnw"))) {
1627 "Unknown connect error (unsupported authentication method?)\n");
1630 cptr += strlen(
"authmod=");
1631 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1632 authmod[i++] = *cptr++;
1640 if (strstr(desc,
"?reason=authfailed")) {
1643 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1655 if (strstr(desc,
"code=403 need auth")) {
1657 "?authmod=%s&user=%s", authmod, rt->
username);
1661 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1670 char *next = strchr(ptr,
'&');
1671 char *
value = strchr(ptr,
'=');
1676 if (!strcmp(ptr,
"user")) {
1678 }
else if (!strcmp(ptr,
"salt")) {
1680 }
else if (!strcmp(ptr,
"opaque")) {
1682 }
else if (!strcmp(ptr,
"challenge")) {
1684 }
else if (!strcmp(ptr,
"nonce")) {
1690 if (!strcmp(authmod,
"adobe")) {
1691 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1706 char *tracked_method = NULL;
1715 "description", tmpstr,
sizeof(tmpstr))) {
1716 if (tracked_method && (!strcmp(tracked_method,
"_checkbw") ||
1717 !strcmp(tracked_method,
"releaseStream") ||
1718 !strcmp(tracked_method,
"FCSubscribe") ||
1719 !strcmp(tracked_method,
"FCPublish"))) {
1723 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1731 av_log(s, level,
"Server error: %s\n", tmpstr);
1744 char statusmsg[128];
1766 if (!strcmp(command,
"FCPublish") ||
1767 !strcmp(command,
"publish")) {
1769 sizeof(filename), &stringlen);
1775 "Unable to find / in url %s, bad format\n",
1780 if (strcmp(pchar, filename))
1782 " %s\n", filename, pchar);
1787 if (!strcmp(command,
"FCPublish")) {
1796 }
else if (!strcmp(command,
"publish")) {
1806 bytestream2_put_be16(&pbc, 0);
1833 snprintf(statusmsg,
sizeof(statusmsg),
1834 "%s is now published", filename);
1854 if (!strcmp(command,
"createStream")) {
1874 char *tracked_method = NULL;
1880 if (!tracked_method) {
1885 if (!memcmp(tracked_method,
"connect", 7)) {
1906 }
else if (rt->
live == -1) {
1911 }
else if (!memcmp(tracked_method,
"createStream", 12)) {
1913 if (pkt->
data[10] || pkt->
data[19] != 5 || pkt->
data[20]) {
1943 for (i = 0; i < 2; i++) {
1951 if (!t && !strcmp(tmpstr,
"error")) {
1953 "description", tmpstr,
sizeof(tmpstr)))
1961 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
1973 if (!memcmp(pkt->
data,
"\002\000\006_error", 9)) {
1976 }
else if (!memcmp(pkt->
data,
"\002\000\007_result", 10)) {
1979 }
else if (!memcmp(pkt->
data,
"\002\000\010onStatus", 11)) {
1982 }
else if (!memcmp(pkt->
data,
"\002\000\010onBWDone", 11)) {
1985 }
else if (!memcmp(pkt->
data,
"\002\000\015releaseStream", 16) ||
1986 !memcmp(pkt->
data,
"\002\000\011FCPublish", 12) ||
1987 !memcmp(pkt->
data,
"\002\000\007publish", 10) ||
1988 !memcmp(pkt->
data,
"\002\000\010_checkbw", 11) ||
1989 !memcmp(pkt->
data,
"\002\000\014createStream", 15)) {
2002 char statusmsg[128];
2009 unsigned datatowritelength;
2016 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2017 datatowrite = gbc.
buffer;
2020 sizeof(statusmsg), &stringlen))
2022 if (strcmp(statusmsg,
"onMetaData")) {
2034 rt->
flv_size += datatowritelength + 15;
2037 rt->
flv_size = datatowritelength + 15;
2047 bytestream2_put_byte(&pbc, pkt->
type);
2048 bytestream2_put_be24(&pbc, datatowritelength);
2049 bytestream2_put_be24(&pbc, ts);
2050 bytestream2_put_byte(&pbc, ts >> 24);
2051 bytestream2_put_be24(&pbc, 0);
2053 bytestream2_put_be32(&pbc, 0);
2072 switch (pkt->
type) {
2074 av_dlog(s,
"received bytes read report\n");
2127 uint32_t ts, cts, pts=0;
2181 bytestream_put_byte(&p, rpkt.
type);
2182 bytestream_put_be24(&p, rpkt.
data_size);
2183 bytestream_put_be24(&p, ts);
2184 bytestream_put_byte(&p, ts >> 24);
2185 bytestream_put_be24(&p, 0);
2187 bytestream_put_be32(&p, 0);
2208 data_size = bytestream_get_be24(&next);
2210 cts = bytestream_get_be24(&next);
2211 cts |= bytestream_get_byte(&next) << 24;
2216 bytestream_put_be24(&p, ts);
2217 bytestream_put_byte(&p, ts >> 24);
2218 next += data_size + 3 + 4;
2261 char proto[8], hostname[256], path[1024], auth[100], *fname;
2274 hostname,
sizeof(hostname), &port,
2278 char *ptr = strchr(auth,
':');
2286 if (rt->
listen && strcmp(proto,
"rtmp")) {
2291 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2292 if (!strcmp(proto,
"rtmpts"))
2296 ff_url_join(buf,
sizeof(buf),
"ffrtmphttp", NULL, hostname, port, NULL);
2297 }
else if (!strcmp(proto,
"rtmps")) {
2301 ff_url_join(buf,
sizeof(buf),
"tls", NULL, hostname, port, NULL);
2302 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2303 if (!strcmp(proto,
"rtmpte"))
2304 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2307 ff_url_join(buf,
sizeof(buf),
"ffrtmpcrypt", NULL, hostname, port, NULL);
2314 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port,
2315 "?listen&listen_timeout=%d",
2318 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port, NULL);
2353 if (!strncmp(path,
"/ondemand/", 10)) {
2355 memcpy(rt->
app,
"ondemand", 9);
2357 char *next = *path ? path + 1 : path;
2358 char *p = strchr(next,
'/');
2364 char *
c = strchr(p + 1,
':');
2365 fname = strchr(p + 1,
'/');
2366 if (!fname || (c && c < fname)) {
2387 int len = strlen(fname);
2395 if (!strchr(fname,
':') && len >= 4 &&
2396 (!strcmp(fname + len - 4,
".f4v") ||
2397 !strcmp(fname + len - 4,
".mp4"))) {
2399 }
else if (len >= 4 && !strcmp(fname + len - 4,
".flv")) {
2400 fname[len - 4] =
'\0';
2414 port,
"/%s", rt->
app);
2451 }
while (ret == EAGAIN);
2491 int orig_size =
size;
2497 if (data_left >= size) {
2502 if (data_left > 0) {
2518 int size_temp =
size;
2519 int pktsize, pkttype;
2543 pkttype = bytestream_get_byte(&header);
2544 pktsize = bytestream_get_be24(&header);
2545 ts = bytestream_get_be24(&header);
2546 ts |= bytestream_get_byte(&header) << 24;
2547 bytestream_get_be24(&header);
2560 pkttype, ts, pktsize)) < 0)
2590 }
while (buf_temp - buf < size);
2608 }
else if (ret < 0) {
2610 }
else if (ret == 1) {
2627 #define OFFSET(x) offsetof(RTMPContext, x)
2628 #define DEC AV_OPT_FLAG_DECODING_PARAM
2629 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2633 {
"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},
2635 {
"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},
2636 {
"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},
2637 {
"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"},
2641 {
"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},
2643 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2645 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
2647 {
"rtmp_swfverify",
"URL to player swf file, compute hash/size automatically.",
OFFSET(swfverify),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2648 {
"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},
2649 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2650 {
"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" },
2654 #define RTMP_PROTOCOL(flavor) \
2655 static const AVClass flavor##_class = { \
2656 .class_name = #flavor, \
2657 .item_name = av_default_item_name, \
2658 .option = rtmp_options, \
2659 .version = LIBAVUTIL_VERSION_INT, \
2662 URLProtocol ff_##flavor##_protocol = { \
2664 .url_open = rtmp_open, \
2665 .url_read = rtmp_read, \
2666 .url_write = rtmp_write, \
2667 .url_close = rtmp_close, \
2668 .priv_data_size = sizeof(RTMPContext), \
2669 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2670 .priv_data_class= &flavor##_class, \