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
130 #define PLAYER_KEY_OPEN_PART_LEN 30
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',
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
141 #define SERVER_KEY_OPEN_PART_LEN 36
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',
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
184 char **tracked_method)
260 if (param[0] && param[1] ==
':') {
263 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
266 value = strchr(field,
':');
272 if (!field || !value)
370 char *param = rt->
conn;
373 while (param !=
NULL) {
375 param += strspn(param,
" ");
378 sep = strchr(param,
' ');
421 if (strcmp(command,
"connect")) {
432 "app", tmpstr,
sizeof(tmpstr));
435 if (!ret && strcmp(tmpstr, rt->
app))
458 bytestream_put_byte(&p, 2);
472 bytestream_put_be16(&p, 0);
473 bytestream_put_be32(&p, 0);
680 bytestream_put_be16(&p, 3);
774 if (ppkt->
size < 6) {
785 bytestream_put_be16(&p, 7);
806 bytestream_put_be16(&p, 27);
872 const char *subscribe)
879 0, 27 + strlen(subscribe))) < 0)
903 memcpy(hmac_buf, key, keylen);
909 for (i = 0; i < 64; i++)
922 for (i = 0; i < 64; i++)
936 int i, digest_pos = 0;
938 for (i = 0; i < 4; i++)
939 digest_pos += buf[i + off];
940 digest_pos = digest_pos % mod_val + add_val;
991 if (!memcmp(digest, buf + digest_pos, 32))
1004 "Hash of the decompressed SWF file is not 32 bytes long.\n");
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);
1021 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
1022 uint8_t **out_data, int64_t *out_size)
1024 z_stream zs = { 0 };
1029 zs.avail_in = in_size;
1030 zs.next_in = in_data;
1031 ret = inflateInit(&zs);
1038 zs.avail_out =
sizeof(tmp_buf);
1039 zs.next_out = tmp_buf;
1041 ret = inflate(&zs, Z_NO_FLUSH);
1042 if (ret != Z_OK && ret != Z_STREAM_END) {
1047 size =
sizeof(tmp_buf) - zs.avail_out;
1048 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1054 memcpy(*out_data + *out_size, tmp_buf, size);
1056 }
while (zs.avail_out == 0);
1068 int64_t in_size, out_size;
1099 if (!memcmp(in_data,
"CWS", 3)) {
1106 memcpy(out_data, in_data, 8);
1110 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1111 &out_data, &out_size)) < 0)
1115 "Zlib is required for decompressing the SWF player file.\n");
1128 "Genuine Adobe Flash Player 001", 30,
1163 int server_pos, client_pos;
1214 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1216 if (rt->
is_input && serverdata[5] >= 3) {
1248 0, digest, 32, signature);
1256 tosend + 1, type)) < 0)
1278 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1285 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1291 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1304 tosend + 1, 1)) < 0)
1307 if (serverdata[0] == 9) {
1329 uint32_t *second_int,
char *arraydata,
1340 " not following standard\n", (
int)inoutsize);
1344 *first_int =
AV_RB32(arraydata);
1345 *second_int =
AV_RB32(arraydata + 4);
1350 uint32_t second_int,
char *arraydata,
int size)
1354 AV_WB32(arraydata, first_int);
1355 AV_WB32(arraydata + 4, second_int);
1373 uint32_t hs_my_epoch;
1383 if (inoutsize <= 0) {
1388 if (buffer[0] != 3) {
1394 "Unable to write answer - RTMP S0\n");
1406 hs_my_epoch = hs_epoch;
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");
1448 if (pkt->
size < 4) {
1450 "Too short chunk size change packet (%d)\n",
1481 if (pkt->
size < 2) {
1489 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1491 }
else if (t == 26) {
1507 if (pkt->
size < 4) {
1509 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1531 if (pkt->
size < 4) {
1533 "Too short server bandwidth report packet (%d)\n",
1550 const char *opaque,
const char *challenge)
1578 "?authmod=%s&user=%s&challenge=%s&response=%s",
1579 "adobe", user, challenge2, hashstr);
1582 "&opaque=%s", opaque);
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";
1611 hashstr1[32] =
'\0';
1617 if (!strchr(rt->
app,
'/'))
1621 hashstr2[32] =
'\0';
1640 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1641 "llnw", user, nonce, cnonce, nc, hashstr1);
1650 char buf[300], *ptr, authmod[15];
1652 const char *user =
"", *salt =
"", *opaque =
NULL,
1655 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1656 !(cptr = strstr(desc,
"authmod=llnw"))) {
1658 "Unknown connect error (unsupported authentication method?)\n");
1661 cptr += strlen(
"authmod=");
1662 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1663 authmod[i++] = *cptr++;
1671 if (strstr(desc,
"?reason=authfailed")) {
1674 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1686 if (strstr(desc,
"code=403 need auth")) {
1688 "?authmod=%s&user=%s", authmod, rt->
username);
1692 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1701 char *next = strchr(ptr,
'&');
1702 char *value = strchr(ptr,
'=');
1707 if (!strcmp(ptr,
"user")) {
1709 }
else if (!strcmp(ptr,
"salt")) {
1711 }
else if (!strcmp(ptr,
"opaque")) {
1713 }
else if (!strcmp(ptr,
"challenge")) {
1715 }
else if (!strcmp(ptr,
"nonce")) {
1721 if (!strcmp(authmod,
"adobe")) {
1722 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1737 char *tracked_method =
NULL;
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"))) {
1754 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1762 av_log(s, level,
"Server error: %s\n", tmpstr);
1784 bytestream2_put_be16(&pbc, 0);
1796 const char *status,
const char *filename)
1800 char statusmsg[128];
1823 snprintf(statusmsg,
sizeof(statusmsg),
1824 "%s is now published", filename);
1868 if (!strcmp(command,
"FCPublish") ||
1869 !strcmp(command,
"publish")) {
1871 sizeof(filename), &stringlen);
1877 "Unable to find / in url %s, bad format\n",
1882 if (strcmp(pchar, filename))
1884 " %s\n", filename, pchar);
1889 if (!strcmp(command,
"FCPublish")) {
1898 }
else if (!strcmp(command,
"publish")) {
1906 }
else if (!strcmp(command,
"play")) {
1924 if (!strcmp(command,
"createStream")) {
1944 char *tracked_method =
NULL;
1950 if (!tracked_method) {
1955 if (!strcmp(tracked_method,
"connect")) {
1976 }
else if (rt->
live == -1) {
1981 }
else if (!strcmp(tracked_method,
"createStream")) {
1983 if (pkt->
data[10] || pkt->
data[19] != 5 || pkt->
data[20]) {
2013 for (i = 0; i < 2; i++) {
2021 if (!t && !strcmp(tmpstr,
"error")) {
2023 "description", tmpstr,
sizeof(tmpstr));
2024 if (t || !tmpstr[0])
2026 tmpstr,
sizeof(tmpstr));
2035 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
2089 return old_flv_size;
2094 int old_flv_size, ret;
2097 const int size = pkt->
size - skip;
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);
2114 bytestream2_put_be32(&pbc, 0);
2123 char statusmsg[128];
2124 int stringlen, ret, skip = 0;
2133 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2136 sizeof(statusmsg), &stringlen);
2158 switch (pkt->
type) {
2160 av_dlog(s,
"received bytes read report\n");
2197 int ret, old_flv_size, type;
2201 uint32_t ts, cts, pts = 0;
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;
2225 if (size + 3 + 4 > pkt->
data + pkt->
size - next)
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;
2237 "RTMP_PT_METADATA packet\n");
2348 for (i = 0; i < 2; i++) {
2372 char proto[8], hostname[256], path[1024], auth[100], *fname;
2385 hostname,
sizeof(hostname), &port,
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");
2396 char *ptr = strchr(auth,
':');
2404 if (rt->
listen && strcmp(proto,
"rtmp")) {
2409 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2410 if (!strcmp(proto,
"rtmpts"))
2415 }
else if (!strcmp(proto,
"rtmps")) {
2420 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2421 if (!strcmp(proto,
"rtmpte"))
2422 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2433 "?listen&listen_timeout=%d",
2471 if (!strncmp(path,
"/ondemand/", 10)) {
2473 memcpy(rt->
app,
"ondemand", 9);
2475 char *next = *path ? path + 1 : path;
2476 char *p = strchr(next,
'/');
2482 char *c = strchr(p + 1,
':');
2483 fname = strchr(p + 1,
'/');
2484 if (!fname || (c && c < fname)) {
2501 int len = strlen(fname);
2509 if (!strchr(fname,
':') && len >= 4 &&
2510 (!strcmp(fname + len - 4,
".f4v") ||
2511 !strcmp(fname + len - 4,
".mp4"))) {
2514 if (len >= 4 && !strcmp(fname + len - 4,
".flv"))
2515 fname[len - 4] =
'\0';
2528 port,
"/%s", rt->
app);
2564 }
while (ret ==
AVERROR(EAGAIN));
2574 for (i = 0; i < 2; i++)
2609 int orig_size =
size;
2615 if (data_left >= size) {
2620 if (data_left > 0) {
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) {
2643 "Unable to send seek command on stream index %d at timestamp "
2644 "%"PRId64
" with flags %08x\n",
2645 stream_index, timestamp, flags);
2656 int size_temp =
size;
2657 int pktsize, pkttype;
2659 const uint8_t *buf_temp = buf;
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);
2706 pkttype, ts, pktsize)) < 0)
2736 }
while (buf_temp - buf < size);
2754 }
else if (ret < 0) {
2756 }
else if (ret == 1) {
2774 #define OFFSET(x) offsetof(RTMPContext, x)
2775 #define DEC AV_OPT_FLAG_DECODING_PARAM
2776 #define ENC AV_OPT_FLAG_ENCODING_PARAM
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},
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"},
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},
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},
2792 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
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" },
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, \
2810 URLProtocol ff_##flavor##_protocol = { \
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, \