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
135 #define PLAYER_KEY_OPEN_PART_LEN 30
138 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
139 'F',
'l',
'a',
's',
'h',
' ',
'P',
'l',
'a',
'y',
'e',
'r',
' ',
'0',
'0',
'1',
141 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
142 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
143 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
146 #define SERVER_KEY_OPEN_PART_LEN 36
149 'G',
'e',
'n',
'u',
'i',
'n',
'e',
' ',
'A',
'd',
'o',
'b',
'e',
' ',
150 'F',
'l',
'a',
's',
'h',
' ',
'M',
'e',
'd',
'i',
'a',
' ',
151 'S',
'e',
'r',
'v',
'e',
'r',
' ',
'0',
'0',
'1',
153 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
154 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
155 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
191 char **tracked_method)
266 if (param[0] && param[1] ==
':') {
269 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
272 value = strchr(field,
':');
373 char *param = rt->
conn;
378 param += strspn(param,
" ");
381 sep = strchr(param,
' ');
435 if (strcmp(command,
"connect")) {
446 "app", tmpstr,
sizeof(tmpstr));
449 if (!ret && strcmp(tmpstr, rt->
app))
472 bytestream_put_byte(&p, 2);
486 bytestream_put_be16(&p, 0);
487 bytestream_put_be32(&p, 0);
718 bytestream_put_be16(&p, 3);
839 if (ppkt->
size < 6) {
850 bytestream_put_be16(&p, 7);
871 bytestream_put_be16(&p, 27);
937 const char *subscribe)
944 0, 27 + strlen(subscribe))) < 0)
968 memcpy(hmac_buf, key, keylen);
974 for (i = 0; i < 64; i++)
987 for (i = 0; i < 64; i++)
1001 int i, digest_pos = 0;
1003 for (i = 0; i < 4; i++)
1004 digest_pos += buf[i + off];
1005 digest_pos = digest_pos % mod_val + add_val;
1020 int ret, digest_pos;
1046 int ret, digest_pos;
1056 if (!memcmp(digest, buf + digest_pos, 32))
1069 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1074 bytestream_put_byte(&p, 1);
1075 bytestream_put_byte(&p, 1);
1076 bytestream_put_be32(&p, rt->
swfsize);
1077 bytestream_put_be32(&p, rt->
swfsize);
1086 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
1087 uint8_t **out_data, int64_t *out_size)
1089 z_stream zs = { 0 };
1094 zs.avail_in = in_size;
1095 zs.next_in = in_data;
1096 ret = inflateInit(&zs);
1103 zs.avail_out =
sizeof(tmp_buf);
1104 zs.next_out = tmp_buf;
1106 ret = inflate(&zs, Z_NO_FLUSH);
1107 if (ret != Z_OK && ret != Z_STREAM_END) {
1112 size =
sizeof(tmp_buf) - zs.avail_out;
1113 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1119 memcpy(*out_data + *out_size, tmp_buf, size);
1121 }
while (zs.avail_out == 0);
1133 int64_t in_size, out_size;
1164 if (!memcmp(in_data,
"CWS", 3)) {
1171 memcpy(out_data, in_data, 8);
1175 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1176 &out_data, &out_size)) < 0)
1180 "Zlib is required for decompressing the SWF player file.\n");
1193 "Genuine Adobe Flash Player 001", 30,
1228 int server_pos, client_pos;
1239 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1279 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1281 if (rt->
is_input && serverdata[5] >= 3) {
1313 0, digest, 32, signature);
1317 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1321 tosend + 1, type)) < 0)
1343 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1347 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1350 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1356 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1359 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1365 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1369 tosend + 1, 1)) < 0)
1372 if (serverdata[0] == 9) {
1383 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1394 uint32_t *second_int,
char *arraydata,
1405 " not following standard\n", (
int)inoutsize);
1409 *first_int =
AV_RB32(arraydata);
1410 *second_int =
AV_RB32(arraydata + 4);
1415 uint32_t second_int,
char *arraydata,
int size)
1419 AV_WB32(arraydata, first_int);
1420 AV_WB32(arraydata + 4, second_int);
1438 uint32_t hs_my_epoch;
1448 if (inoutsize <= 0) {
1453 if (buffer[0] != 3) {
1459 "Unable to write answer - RTMP S0\n");
1471 hs_my_epoch = hs_epoch;
1497 if (temp != hs_my_epoch)
1499 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1500 if (memcmp(buffer + 8, hs_s1 + 8,
1503 "Erroneous C2 Message random does not match up\n");
1513 if (pkt->
size < 4) {
1515 "Too short chunk size change packet (%d)\n",
1546 if (pkt->
size < 2) {
1554 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1556 }
else if (t == 26) {
1572 if (pkt->
size < 4) {
1574 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1596 if (pkt->
size < 4) {
1598 "Too short server bandwidth report packet (%d)\n",
1615 const char *opaque,
const char *challenge)
1643 "?authmod=%s&user=%s&challenge=%s&response=%s",
1644 "adobe", user, challenge2, hashstr);
1647 "&opaque=%s", opaque);
1656 char hashstr1[33], hashstr2[33];
1657 const char *realm =
"live";
1658 const char *method =
"publish";
1659 const char *qop =
"auth";
1660 const char *nc =
"00000001";
1676 hashstr1[32] =
'\0';
1682 if (!strchr(rt->
app,
'/'))
1686 hashstr2[32] =
'\0';
1705 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1706 "llnw", user, nonce, cnonce, nc, hashstr1);
1715 char buf[300], *ptr, authmod[15];
1717 const char *user =
"", *salt =
"", *opaque =
NULL,
1720 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1721 !(cptr = strstr(desc,
"authmod=llnw"))) {
1723 "Unknown connect error (unsupported authentication method?)\n");
1726 cptr += strlen(
"authmod=");
1727 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1728 authmod[i++] = *cptr++;
1736 if (strstr(desc,
"?reason=authfailed")) {
1739 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1751 if (strstr(desc,
"code=403 need auth")) {
1753 "?authmod=%s&user=%s", authmod, rt->
username);
1757 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1766 char *next = strchr(ptr,
'&');
1767 char *
value = strchr(ptr,
'=');
1772 if (!strcmp(ptr,
"user")) {
1774 }
else if (!strcmp(ptr,
"salt")) {
1776 }
else if (!strcmp(ptr,
"opaque")) {
1778 }
else if (!strcmp(ptr,
"challenge")) {
1780 }
else if (!strcmp(ptr,
"nonce")) {
1791 if (!strcmp(authmod,
"adobe")) {
1792 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1807 char *tracked_method =
NULL;
1816 "description", tmpstr,
sizeof(tmpstr))) {
1817 if (tracked_method && (!strcmp(tracked_method,
"_checkbw") ||
1818 !strcmp(tracked_method,
"releaseStream") ||
1819 !strcmp(tracked_method,
"FCSubscribe") ||
1820 !strcmp(tracked_method,
"FCPublish"))) {
1824 }
else if (tracked_method && !strcmp(tracked_method,
"getStreamLength")) {
1827 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1835 av_log(s, level,
"Server error: %s\n", tmpstr);
1857 bytestream2_put_be16(&pbc, 0);
1869 const char *status,
const char *filename)
1873 char statusmsg[128];
1896 snprintf(statusmsg,
sizeof(statusmsg),
1897 "%s is now published", filename);
1941 if (!strcmp(command,
"FCPublish") ||
1942 !strcmp(command,
"publish")) {
1944 sizeof(filename), &stringlen);
1950 "Unable to find / in url %s, bad format\n",
1955 if (strcmp(pchar, filename))
1957 " %s\n", filename, pchar);
1962 if (!strcmp(command,
"FCPublish")) {
1971 }
else if (!strcmp(command,
"publish")) {
1979 }
else if (!strcmp(command,
"play")) {
1997 if (!strcmp(command,
"createStream")) {
2036 if (strcmp(strbuffer,
"_result"))
2048 *number = numbuffer;
2056 char *tracked_method =
NULL;
2062 if (!tracked_method) {
2067 if (!strcmp(tracked_method,
"connect")) {
2088 }
else if (rt->
live == -1) {
2093 }
else if (!strcmp(tracked_method,
"createStream")) {
2105 if (rt->
live != -1) {
2114 }
else if (!strcmp(tracked_method,
"getStreamLength")) {
2133 for (i = 0; i < 2; i++) {
2141 if (!t && !strcmp(tmpstr,
"error")) {
2143 "description", tmpstr,
sizeof(tmpstr));
2144 if (t || !tmpstr[0])
2146 tmpstr,
sizeof(tmpstr));
2155 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
2209 return old_flv_size;
2214 int old_flv_size,
ret;
2217 const int size = pkt->
size - skip;
2234 bytestream2_put_byte(&pbc, pkt->
type);
2235 bytestream2_put_be24(&pbc, size);
2236 bytestream2_put_be24(&pbc, ts);
2237 bytestream2_put_byte(&pbc, ts >> 24);
2238 bytestream2_put_be24(&pbc, 0);
2240 bytestream2_put_be32(&pbc, 0);
2249 char statusmsg[128];
2250 int stringlen,
ret, skip = 0;
2258 if (!strcmp(commandbuffer,
"onMetaData")) {
2278 if (!strcmp(statusmsg,
"videocodecid")) {
2281 if (!strcmp(statusmsg,
"audiocodecid")) {
2291 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2294 sizeof(statusmsg), &stringlen);
2316 switch (pkt->
type) {
2318 av_dlog(s,
"received bytes read report\n");
2359 uint32_t ts, cts,
pts = 0;
2375 type = bytestream_get_byte(&next);
2376 size = bytestream_get_be24(&next);
2377 cts = bytestream_get_be24(&next);
2378 cts |= bytestream_get_byte(&next) << 24;
2383 if (size + 3 + 4 > pkt->
data + pkt->
size - next)
2385 bytestream_put_byte(&p, type);
2386 bytestream_put_be24(&p, size);
2387 bytestream_put_be24(&p, ts);
2388 bytestream_put_byte(&p, ts >> 24);
2389 memcpy(p, next, size + 3 + 4);
2390 next += size + 3 + 4;
2395 "RTMP_PT_METADATA packet\n");
2510 for (i = 0; i < 2; i++) {
2548 memcpy(rt->
flv_data, old_flv_data, 13);
2558 bytestream_put_be24(&p, 40);
2559 bytestream_put_be24(&p, 0);
2560 bytestream_put_be32(&p, 0);
2565 bytestream_put_be16(&p, 10);
2570 bytestream_put_be32(&p, 1);
2573 bytestream_put_be16(&p, 8);
2579 bytestream_put_be16(&p, 0);
2581 bytestream_put_be32(&p, 40);
2598 char proto[8], hostname[256], path[1024], auth[100], *fname;
2599 char *old_app, *qmark, *
n, fname_buffer[1024];
2611 hostname,
sizeof(hostname), &port,
2614 n = strchr(path,
' ');
2617 "Detected librtmp style URL parameters, these aren't supported "
2618 "by the libavformat internal RTMP handler currently enabled. "
2619 "See the documentation for the correct way to pass parameters.\n");
2624 char *ptr = strchr(auth,
':');
2632 if (rt->
listen && strcmp(proto,
"rtmp")) {
2637 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2638 if (!strcmp(proto,
"rtmpts"))
2643 }
else if (!strcmp(proto,
"rtmps")) {
2648 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2649 if (!strcmp(proto,
"rtmpte"))
2650 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2661 "?listen&listen_timeout=%d",
2699 qmark = strchr(path,
'?');
2700 if (qmark && strstr(qmark,
"slist=")) {
2704 fname = strstr(path,
"slist=") + 6;
2706 amp = strchr(fname,
'&');
2709 sizeof(fname_buffer)));
2710 fname = fname_buffer;
2712 }
else if (!strncmp(path,
"/ondemand/", 10)) {
2714 memcpy(rt->
app,
"ondemand", 9);
2716 char *next = *path ? path + 1 : path;
2717 char *p = strchr(next,
'/');
2729 char *
c = strchr(p + 1,
':');
2730 fname = strchr(p + 1,
'/');
2731 if (!fname || (c && c < fname)) {
2759 int len = strlen(fname);
2760 if (!strchr(fname,
':') && len >= 4 &&
2761 (!strcmp(fname + len - 4,
".f4v") ||
2762 !strcmp(fname + len - 4,
".mp4"))) {
2765 if (len >= 4 && !strcmp(fname + len - 4,
".flv"))
2766 fname[len - 4] =
'\0';
2782 port,
"/%s", rt->
app);
2822 }
while (ret ==
AVERROR(EAGAIN));
2832 for (i = 0; i < 2; i++)
2894 int orig_size =
size;
2900 if (data_left >= size) {
2905 if (data_left > 0) {
2924 "Seek on stream index %d at timestamp %"PRId64
" with flags %08x\n",
2925 stream_index, timestamp, flags);
2926 if ((ret =
gen_seek(s, rt, timestamp)) < 0) {
2928 "Unable to send seek command on stream index %d at timestamp "
2929 "%"PRId64
" with flags %08x\n",
2930 stream_index, timestamp, flags);
2955 int size_temp =
size;
2956 int pktsize, pkttype,
copy;
2982 pkttype = bytestream_get_byte(&header);
2983 pktsize = bytestream_get_be24(&header);
2984 ts = bytestream_get_be24(&header);
2985 ts |= bytestream_get_byte(&header) << 24;
2986 bytestream_get_be24(&header);
3006 pkttype, ts, pktsize)) < 0)
3033 if (!strcmp(commandbuffer,
"onMetaData") ||
3034 !strcmp(commandbuffer,
"|RtmpSampleAccess")) {
3055 }
while (buf_temp - buf < size);
3073 }
else if (ret < 0) {
3075 }
else if (ret == 1) {
3093 #define OFFSET(x) offsetof(RTMPContext, x)
3094 #define DEC AV_OPT_FLAG_DECODING_PARAM
3095 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3099 {
"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},
3102 {
"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},
3103 {
"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"},
3107 {
"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},
3109 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str =
NULL }, 0, 0,
DEC},
3111 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
3115 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
3116 {
"listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
3117 {
"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" },
3121 #define RTMP_PROTOCOL(flavor) \
3122 static const AVClass flavor##_class = { \
3123 .class_name = #flavor, \
3124 .item_name = av_default_item_name, \
3125 .option = rtmp_options, \
3126 .version = LIBAVUTIL_VERSION_INT, \
3129 URLProtocol ff_##flavor##_protocol = { \
3131 .url_open = rtmp_open, \
3132 .url_read = rtmp_read, \
3133 .url_read_seek = rtmp_seek, \
3134 .url_read_pause = rtmp_pause, \
3135 .url_write = rtmp_write, \
3136 .url_close = rtmp_close, \
3137 .priv_data_size = sizeof(RTMPContext), \
3138 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3139 .priv_data_class= &flavor##_class, \