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
133 #define PLAYER_KEY_OPEN_PART_LEN 30
136 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
137 'F',
'l',
'a',
's',
'h',
' ',
'P',
'l',
'a',
'y',
'e',
'r',
' ',
'0',
'0',
'1',
139 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
140 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
141 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
144 #define SERVER_KEY_OPEN_PART_LEN 36
147 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
148 'F',
'l',
'a',
's',
'h',
' ',
'M',
'e',
'd',
'i',
'a',
' ',
149 'S',
'e',
'r',
'v',
'e',
'r',
' ',
'0',
'0',
'1',
151 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
152 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
153 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
189 char **tracked_method)
265 if (param[0] && param[1] ==
':') {
268 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
271 value = strchr(field,
':');
372 char *param = rt->
conn;
377 param += strspn(param,
" ");
380 sep = strchr(param,
' ');
434 if (strcmp(command,
"connect")) {
445 "app", tmpstr,
sizeof(tmpstr));
448 if (!ret && strcmp(tmpstr, rt->
app))
471 bytestream_put_byte(&p, 2);
485 bytestream_put_be16(&p, 0);
486 bytestream_put_be32(&p, 0);
693 bytestream_put_be16(&p, 3);
787 if (ppkt->
size < 6) {
798 bytestream_put_be16(&p, 7);
819 bytestream_put_be16(&p, 27);
885 const char *subscribe)
892 0, 27 + strlen(subscribe))) < 0)
916 memcpy(hmac_buf, key, keylen);
922 for (i = 0; i < 64; i++)
935 for (i = 0; i < 64; i++)
949 int i, digest_pos = 0;
951 for (i = 0; i < 4; i++)
952 digest_pos += buf[i + off];
953 digest_pos = digest_pos % mod_val + add_val;
1004 if (!memcmp(digest, buf + digest_pos, 32))
1017 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1022 bytestream_put_byte(&p, 1);
1023 bytestream_put_byte(&p, 1);
1024 bytestream_put_be32(&p, rt->
swfsize);
1025 bytestream_put_be32(&p, rt->
swfsize);
1034 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
1035 uint8_t **out_data, int64_t *out_size)
1037 z_stream zs = { 0 };
1042 zs.avail_in = in_size;
1043 zs.next_in = in_data;
1044 ret = inflateInit(&zs);
1051 zs.avail_out =
sizeof(tmp_buf);
1052 zs.next_out = tmp_buf;
1054 ret = inflate(&zs, Z_NO_FLUSH);
1055 if (ret != Z_OK && ret != Z_STREAM_END) {
1060 size =
sizeof(tmp_buf) - zs.avail_out;
1061 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1067 memcpy(*out_data + *out_size, tmp_buf, size);
1069 }
while (zs.avail_out == 0);
1080 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1081 int64_t in_size, out_size;
1112 if (!memcmp(in_data,
"CWS", 3)) {
1119 memcpy(out_data, in_data, 8);
1123 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1124 &out_data, &out_size)) < 0)
1128 "Zlib is required for decompressing the SWF player file.\n");
1141 "Genuine Adobe Flash Player 001", 30,
1176 int server_pos, client_pos;
1187 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1227 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1229 if (rt->
is_input && serverdata[5] >= 3) {
1261 0, digest, 32, signature);
1265 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1269 tosend + 1, type)) < 0)
1291 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1295 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1298 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1304 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1307 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1313 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1317 tosend + 1, 1)) < 0)
1320 if (serverdata[0] == 9) {
1331 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1342 uint32_t *second_int,
char *arraydata,
1353 " not following standard\n", (
int)inoutsize);
1357 *first_int =
AV_RB32(arraydata);
1358 *second_int =
AV_RB32(arraydata + 4);
1363 uint32_t second_int,
char *arraydata,
int size)
1367 AV_WB32(arraydata, first_int);
1368 AV_WB32(arraydata + 4, second_int);
1386 uint32_t hs_my_epoch;
1396 if (inoutsize <= 0) {
1401 if (buffer[0] != 3) {
1407 "Unable to write answer - RTMP S0\n");
1419 hs_my_epoch = hs_epoch;
1445 if (temp != hs_my_epoch)
1447 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1448 if (memcmp(buffer + 8, hs_s1 + 8,
1451 "Erroneous C2 Message random does not match up\n");
1461 if (pkt->
size < 4) {
1463 "Too short chunk size change packet (%d)\n",
1494 if (pkt->
size < 2) {
1502 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1504 }
else if (t == 26) {
1520 if (pkt->
size < 4) {
1522 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1544 if (pkt->
size < 4) {
1546 "Too short server bandwidth report packet (%d)\n",
1563 const char *opaque,
const char *challenge)
1591 "?authmod=%s&user=%s&challenge=%s&response=%s",
1592 "adobe", user, challenge2, hashstr);
1595 "&opaque=%s", opaque);
1604 char hashstr1[33], hashstr2[33];
1605 const char *realm =
"live";
1606 const char *method =
"publish";
1607 const char *qop =
"auth";
1608 const char *nc =
"00000001";
1624 hashstr1[32] =
'\0';
1630 if (!strchr(rt->
app,
'/'))
1634 hashstr2[32] =
'\0';
1653 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1654 "llnw", user, nonce, cnonce, nc, hashstr1);
1663 char buf[300], *ptr, authmod[15];
1665 const char *user =
"", *salt =
"", *opaque = NULL,
1666 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1668 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1669 !(cptr = strstr(desc,
"authmod=llnw"))) {
1671 "Unknown connect error (unsupported authentication method?)\n");
1674 cptr += strlen(
"authmod=");
1675 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1676 authmod[i++] = *cptr++;
1684 if (strstr(desc,
"?reason=authfailed")) {
1687 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1699 if (strstr(desc,
"code=403 need auth")) {
1701 "?authmod=%s&user=%s", authmod, rt->
username);
1705 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1714 char *next = strchr(ptr,
'&');
1715 char *
value = strchr(ptr,
'=');
1720 if (!strcmp(ptr,
"user")) {
1722 }
else if (!strcmp(ptr,
"salt")) {
1724 }
else if (!strcmp(ptr,
"opaque")) {
1726 }
else if (!strcmp(ptr,
"challenge")) {
1728 }
else if (!strcmp(ptr,
"nonce")) {
1739 if (!strcmp(authmod,
"adobe")) {
1740 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1755 char *tracked_method = NULL;
1764 "description", tmpstr,
sizeof(tmpstr))) {
1765 if (tracked_method && (!strcmp(tracked_method,
"_checkbw") ||
1766 !strcmp(tracked_method,
"releaseStream") ||
1767 !strcmp(tracked_method,
"FCSubscribe") ||
1768 !strcmp(tracked_method,
"FCPublish"))) {
1772 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1780 av_log(s, level,
"Server error: %s\n", tmpstr);
1802 bytestream2_put_be16(&pbc, 0);
1814 const char *status,
const char *filename)
1818 char statusmsg[128];
1841 snprintf(statusmsg,
sizeof(statusmsg),
1842 "%s is now published", filename);
1886 if (!strcmp(command,
"FCPublish") ||
1887 !strcmp(command,
"publish")) {
1889 sizeof(filename), &stringlen);
1895 "Unable to find / in url %s, bad format\n",
1900 if (strcmp(pchar, filename))
1902 " %s\n", filename, pchar);
1907 if (!strcmp(command,
"FCPublish")) {
1916 }
else if (!strcmp(command,
"publish")) {
1924 }
else if (!strcmp(command,
"play")) {
1942 if (!strcmp(command,
"createStream")) {
1962 char *tracked_method = NULL;
1968 if (!tracked_method) {
1973 if (!strcmp(tracked_method,
"connect")) {
1994 }
else if (rt->
live == -1) {
1999 }
else if (!strcmp(tracked_method,
"createStream")) {
2001 if (pkt->
data[10] || pkt->
data[19] != 5 || pkt->
data[20]) {
2031 for (i = 0; i < 2; i++) {
2039 if (!t && !strcmp(tmpstr,
"error")) {
2041 "description", tmpstr,
sizeof(tmpstr));
2042 if (t || !tmpstr[0])
2044 tmpstr,
sizeof(tmpstr));
2053 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
2107 return old_flv_size;
2112 int old_flv_size,
ret;
2115 const int size = pkt->
size - skip;
2132 bytestream2_put_byte(&pbc, pkt->
type);
2133 bytestream2_put_be24(&pbc, size);
2134 bytestream2_put_be24(&pbc, ts);
2135 bytestream2_put_byte(&pbc, ts >> 24);
2136 bytestream2_put_be24(&pbc, 0);
2138 bytestream2_put_be32(&pbc, 0);
2147 char statusmsg[128];
2148 int stringlen,
ret, skip = 0;
2156 if (!strcmp(commandbuffer,
"onMetaData")) {
2176 if (!strcmp(statusmsg,
"videocodecid")) {
2179 if (!strcmp(statusmsg,
"audiocodecid")) {
2189 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2192 sizeof(statusmsg), &stringlen);
2214 switch (pkt->
type) {
2216 av_dlog(s,
"received bytes read report\n");
2257 uint32_t ts, cts, pts = 0;
2273 type = bytestream_get_byte(&next);
2274 size = bytestream_get_be24(&next);
2275 cts = bytestream_get_be24(&next);
2276 cts |= bytestream_get_byte(&next) << 24;
2281 if (size + 3 + 4 > pkt->
data + pkt->
size - next)
2283 bytestream_put_byte(&p, type);
2284 bytestream_put_be24(&p, size);
2285 bytestream_put_be24(&p, ts);
2286 bytestream_put_byte(&p, ts >> 24);
2287 memcpy(p, next, size + 3 + 4);
2288 next += size + 3 + 4;
2293 "RTMP_PT_METADATA packet\n");
2404 for (i = 0; i < 2; i++) {
2428 char proto[8], hostname[256], path[1024], auth[100], *fname;
2429 char *old_app, *qmark, fname_buffer[1024];
2441 hostname,
sizeof(hostname), &port,
2444 if (strchr(path,
' ')) {
2446 "Detected librtmp style URL parameters, these aren't supported "
2447 "by the libavformat internal RTMP handler currently enabled. "
2448 "See the documentation for the correct way to pass parameters.\n");
2452 char *ptr = strchr(auth,
':');
2460 if (rt->
listen && strcmp(proto,
"rtmp")) {
2465 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2466 if (!strcmp(proto,
"rtmpts"))
2470 ff_url_join(buf,
sizeof(buf),
"ffrtmphttp", NULL, hostname, port, NULL);
2471 }
else if (!strcmp(proto,
"rtmps")) {
2475 ff_url_join(buf,
sizeof(buf),
"tls", NULL, hostname, port, NULL);
2476 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2477 if (!strcmp(proto,
"rtmpte"))
2478 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2481 ff_url_join(buf,
sizeof(buf),
"ffrtmpcrypt", NULL, hostname, port, NULL);
2488 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port,
2489 "?listen&listen_timeout=%d",
2492 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port, NULL);
2527 qmark = strchr(path,
'?');
2528 if (qmark && strstr(qmark,
"slist=")) {
2532 fname = strstr(path,
"slist=") + 6;
2534 amp = strchr(fname,
'&');
2537 sizeof(fname_buffer)));
2538 fname = fname_buffer;
2540 }
else if (!strncmp(path,
"/ondemand/", 10)) {
2542 memcpy(rt->
app,
"ondemand", 9);
2544 char *next = *path ? path + 1 : path;
2545 char *p = strchr(next,
'/');
2551 char *
c = strchr(p + 1,
':');
2552 fname = strchr(p + 1,
'/');
2553 if (!fname || (c && c < fname)) {
2574 int len = strlen(fname);
2582 if (!strchr(fname,
':') && len >= 4 &&
2583 (!strcmp(fname + len - 4,
".f4v") ||
2584 !strcmp(fname + len - 4,
".mp4"))) {
2587 if (len >= 4 && !strcmp(fname + len - 4,
".flv"))
2588 fname[len - 4] =
'\0';
2601 port,
"/%s", rt->
app);
2640 }
while (ret ==
AVERROR(EAGAIN));
2650 for (i = 0; i < 2; i++)
2705 int orig_size =
size;
2711 if (data_left >= size) {
2716 if (data_left > 0) {
2735 "Seek on stream index %d at timestamp %"PRId64
" with flags %08x\n",
2736 stream_index, timestamp, flags);
2737 if ((ret =
gen_seek(s, rt, timestamp)) < 0) {
2739 "Unable to send seek command on stream index %d at timestamp "
2740 "%"PRId64
" with flags %08x\n",
2741 stream_index, timestamp, flags);
2752 int size_temp =
size;
2753 int pktsize, pkttype;
2778 pkttype = bytestream_get_byte(&header);
2779 pktsize = bytestream_get_be24(&header);
2780 ts = bytestream_get_be24(&header);
2781 ts |= bytestream_get_byte(&header) << 24;
2782 bytestream_get_be24(&header);
2802 pkttype, ts, pktsize)) < 0)
2832 }
while (buf_temp - buf < size);
2850 }
else if (ret < 0) {
2852 }
else if (ret == 1) {
2870 #define OFFSET(x) offsetof(RTMPContext, x)
2871 #define DEC AV_OPT_FLAG_DECODING_PARAM
2872 #define ENC AV_OPT_FLAG_ENCODING_PARAM
2876 {
"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},
2878 {
"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},
2879 {
"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},
2880 {
"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"},
2884 {
"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},
2886 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2888 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
2890 {
"rtmp_swfverify",
"URL to player swf file, compute hash/size automatically.",
OFFSET(swfverify),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
2891 {
"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},
2892 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2893 {
"listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
2894 {
"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" },
2898 #define RTMP_PROTOCOL(flavor) \
2899 static const AVClass flavor##_class = { \
2900 .class_name = #flavor, \
2901 .item_name = av_default_item_name, \
2902 .option = rtmp_options, \
2903 .version = LIBAVUTIL_VERSION_INT, \
2906 URLProtocol ff_##flavor##_protocol = { \
2908 .url_open = rtmp_open, \
2909 .url_read = rtmp_read, \
2910 .url_read_seek = rtmp_seek, \
2911 .url_write = rtmp_write, \
2912 .url_close = rtmp_close, \
2913 .priv_data_size = sizeof(RTMPContext), \
2914 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2915 .priv_data_class= &flavor##_class, \