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)
267 if (param[0] && param[1] ==
':') {
270 }
else if (param[0] ==
'N' && param[1] && param[2] ==
':') {
273 value = strchr(field,
':');
374 char *param = rt->
conn;
379 param += strspn(param,
" ");
382 sep = strchr(param,
' ');
436 if (strcmp(command,
"connect")) {
447 "app", tmpstr,
sizeof(tmpstr));
450 if (!ret && strcmp(tmpstr, rt->
app))
473 bytestream_put_byte(&p, 2);
487 bytestream_put_be16(&p, 0);
488 bytestream_put_be32(&p, 0);
719 bytestream_put_be16(&p, 3);
840 if (ppkt->
size < 6) {
851 bytestream_put_be16(&p, 7);
872 bytestream_put_be16(&p, 27);
938 const char *subscribe)
945 0, 27 + strlen(subscribe))) < 0)
969 memcpy(hmac_buf, key, keylen);
975 for (i = 0; i < 64; i++)
988 for (i = 0; i < 64; i++)
1002 int i, digest_pos = 0;
1004 for (i = 0; i < 4; i++)
1005 digest_pos += buf[i + off];
1006 digest_pos = digest_pos % mod_val + add_val;
1021 int ret, digest_pos;
1047 int ret, digest_pos;
1057 if (!memcmp(digest, buf + digest_pos, 32))
1070 "Hash of the decompressed SWF file is not 32 bytes long.\n");
1075 bytestream_put_byte(&p, 1);
1076 bytestream_put_byte(&p, 1);
1077 bytestream_put_be32(&p, rt->
swfsize);
1078 bytestream_put_be32(&p, rt->
swfsize);
1087 static int rtmp_uncompress_swfplayer(
uint8_t *in_data, int64_t in_size,
1088 uint8_t **out_data, int64_t *out_size)
1090 z_stream zs = { 0 };
1095 zs.avail_in = in_size;
1096 zs.next_in = in_data;
1097 ret = inflateInit(&zs);
1104 zs.avail_out =
sizeof(tmp_buf);
1105 zs.next_out = tmp_buf;
1107 ret = inflate(&zs, Z_NO_FLUSH);
1108 if (ret != Z_OK && ret != Z_STREAM_END) {
1113 size =
sizeof(tmp_buf) - zs.avail_out;
1114 if (!(ptr =
av_realloc(*out_data, *out_size + size))) {
1120 memcpy(*out_data + *out_size, tmp_buf, size);
1122 }
while (zs.avail_out == 0);
1133 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1134 int64_t in_size, out_size;
1165 if (!memcmp(in_data,
"CWS", 3)) {
1172 memcpy(out_data, in_data, 8);
1176 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1177 &out_data, &out_size)) < 0)
1181 "Zlib is required for decompressing the SWF player file.\n");
1194 "Genuine Adobe Flash Player 001", 30,
1229 int server_pos, client_pos;
1240 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1280 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1282 if (rt->
is_input && serverdata[5] >= 3) {
1314 0, digest, 32, signature);
1318 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1322 tosend + 1, type)) < 0)
1344 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
1348 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1351 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1357 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1360 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1366 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1370 tosend + 1, 1)) < 0)
1373 if (serverdata[0] == 9) {
1384 if (CONFIG_FFRTMPCRYPT_PROTOCOL && rt->
encrypted) {
1395 uint32_t *second_int,
char *arraydata,
1406 " not following standard\n", (
int)inoutsize);
1410 *first_int =
AV_RB32(arraydata);
1411 *second_int =
AV_RB32(arraydata + 4);
1416 uint32_t second_int,
char *arraydata,
int size)
1420 AV_WB32(arraydata, first_int);
1421 AV_WB32(arraydata + 4, second_int);
1439 uint32_t hs_my_epoch;
1449 if (inoutsize <= 0) {
1454 if (buffer[0] != 3) {
1460 "Unable to write answer - RTMP S0\n");
1472 hs_my_epoch = hs_epoch;
1498 if (temp != hs_my_epoch)
1500 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1501 if (memcmp(buffer + 8, hs_s1 + 8,
1504 "Erroneous C2 Message random does not match up\n");
1514 if (pkt->
size < 4) {
1516 "Too short chunk size change packet (%d)\n",
1547 if (pkt->
size < 2) {
1555 if ((ret =
gen_pong(s, rt, pkt)) < 0)
1557 }
else if (t == 26) {
1573 if (pkt->
size < 4) {
1575 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1597 if (pkt->
size < 4) {
1599 "Too short server bandwidth report packet (%d)\n",
1616 const char *opaque,
const char *challenge)
1644 "?authmod=%s&user=%s&challenge=%s&response=%s",
1645 "adobe", user, challenge2, hashstr);
1648 "&opaque=%s", opaque);
1657 char hashstr1[33], hashstr2[33];
1658 const char *realm =
"live";
1659 const char *method =
"publish";
1660 const char *qop =
"auth";
1661 const char *nc =
"00000001";
1677 hashstr1[32] =
'\0';
1683 if (!strchr(rt->
app,
'/'))
1687 hashstr2[32] =
'\0';
1706 "?authmod=%s&user=%s&nonce=%s&cnonce=%s&nc=%s&response=%s",
1707 "llnw", user, nonce, cnonce, nc, hashstr1);
1716 char buf[300], *ptr, authmod[15];
1718 const char *user =
"", *salt =
"", *opaque = NULL,
1719 *challenge = NULL, *cptr = NULL, *nonce = NULL;
1721 if (!(cptr = strstr(desc,
"authmod=adobe")) &&
1722 !(cptr = strstr(desc,
"authmod=llnw"))) {
1724 "Unknown connect error (unsupported authentication method?)\n");
1727 cptr += strlen(
"authmod=");
1728 while (*cptr && *cptr !=
' ' && i <
sizeof(authmod) - 1)
1729 authmod[i++] = *cptr++;
1737 if (strstr(desc,
"?reason=authfailed")) {
1740 }
else if (strstr(desc,
"?reason=nosuchuser")) {
1752 if (strstr(desc,
"code=403 need auth")) {
1754 "?authmod=%s&user=%s", authmod, rt->
username);
1758 if (!(cptr = strstr(desc,
"?reason=needauth"))) {
1767 char *next = strchr(ptr,
'&');
1768 char *
value = strchr(ptr,
'=');
1773 if (!strcmp(ptr,
"user")) {
1775 }
else if (!strcmp(ptr,
"salt")) {
1777 }
else if (!strcmp(ptr,
"opaque")) {
1779 }
else if (!strcmp(ptr,
"challenge")) {
1781 }
else if (!strcmp(ptr,
"nonce")) {
1792 if (!strcmp(authmod,
"adobe")) {
1793 if ((ret =
do_adobe_auth(rt, user, salt, opaque, challenge)) < 0)
1808 char *tracked_method = NULL;
1817 "description", tmpstr,
sizeof(tmpstr))) {
1818 if (tracked_method && (!strcmp(tracked_method,
"_checkbw") ||
1819 !strcmp(tracked_method,
"releaseStream") ||
1820 !strcmp(tracked_method,
"FCSubscribe") ||
1821 !strcmp(tracked_method,
"FCPublish"))) {
1825 }
else if (tracked_method && !strcmp(tracked_method,
"getStreamLength")) {
1828 }
else if (tracked_method && !strcmp(tracked_method,
"connect")) {
1836 av_log(s, level,
"Server error: %s\n", tmpstr);
1858 bytestream2_put_be16(&pbc, 0);
1870 const char *status,
const char *filename)
1874 char statusmsg[128];
1897 snprintf(statusmsg,
sizeof(statusmsg),
1898 "%s is now published", filename);
1942 if (!strcmp(command,
"FCPublish") ||
1943 !strcmp(command,
"publish")) {
1945 sizeof(filename), &stringlen);
1951 "Unable to find / in url %s, bad format\n",
1956 if (strcmp(pchar, filename))
1958 " %s\n", filename, pchar);
1963 if (!strcmp(command,
"FCPublish")) {
1972 }
else if (!strcmp(command,
"publish")) {
1980 }
else if (!strcmp(command,
"play")) {
1998 if (!strcmp(command,
"createStream")) {
2037 if (strcmp(strbuffer,
"_result"))
2049 *number = numbuffer;
2057 char *tracked_method = NULL;
2063 if (!tracked_method) {
2068 if (!strcmp(tracked_method,
"connect")) {
2089 }
else if (rt->
live == -1) {
2094 }
else if (!strcmp(tracked_method,
"createStream")) {
2106 if (rt->
live != -1) {
2115 }
else if (!strcmp(tracked_method,
"getStreamLength")) {
2134 for (i = 0; i < 2; i++) {
2142 if (!t && !strcmp(tmpstr,
"error")) {
2144 "description", tmpstr,
sizeof(tmpstr));
2145 if (t || !tmpstr[0])
2147 tmpstr,
sizeof(tmpstr));
2156 if (!t && !strcmp(tmpstr,
"NetStream.Play.UnpublishNotify")) rt->
state =
STATE_STOPPED;
2210 return old_flv_size;
2215 int old_flv_size,
ret;
2218 const int size = pkt->
size - skip;
2235 bytestream2_put_byte(&pbc, pkt->
type);
2236 bytestream2_put_be24(&pbc, size);
2237 bytestream2_put_be24(&pbc, ts);
2238 bytestream2_put_byte(&pbc, ts >> 24);
2239 bytestream2_put_be24(&pbc, 0);
2241 bytestream2_put_be32(&pbc, 0);
2250 char statusmsg[128];
2251 int stringlen,
ret, skip = 0;
2259 if (!strcmp(commandbuffer,
"onMetaData")) {
2279 if (!strcmp(statusmsg,
"videocodecid")) {
2282 if (!strcmp(statusmsg,
"audiocodecid")) {
2292 if (!strcmp(commandbuffer,
"@setDataFrame")) {
2295 sizeof(statusmsg), &stringlen);
2317 switch (pkt->
type) {
2319 av_dlog(s,
"received bytes read report\n");
2360 uint32_t ts, cts, pts = 0;
2376 type = bytestream_get_byte(&next);
2377 size = bytestream_get_be24(&next);
2378 cts = bytestream_get_be24(&next);
2379 cts |= bytestream_get_byte(&next) << 24;
2384 if (size + 3 + 4 > pkt->
data + pkt->
size - next)
2386 bytestream_put_byte(&p, type);
2387 bytestream_put_be24(&p, size);
2388 bytestream_put_be24(&p, ts);
2389 bytestream_put_byte(&p, ts >> 24);
2390 memcpy(p, next, size + 3 + 4);
2391 next += size + 3 + 4;
2396 "RTMP_PT_METADATA packet\n");
2511 for (i = 0; i < 2; i++) {
2549 memcpy(rt->
flv_data, old_flv_data, 13);
2559 bytestream_put_be24(&p, 40);
2560 bytestream_put_be24(&p, 0);
2561 bytestream_put_be32(&p, 0);
2566 bytestream_put_be16(&p, 10);
2571 bytestream_put_be32(&p, 1);
2574 bytestream_put_be16(&p, 8);
2580 bytestream_put_be16(&p, 0);
2582 bytestream_put_be32(&p, 40);
2599 char proto[8], hostname[256], path[1024], auth[100], *fname;
2600 char *old_app, *qmark, *
n, fname_buffer[1024];
2612 hostname,
sizeof(hostname), &port,
2615 n = strchr(path,
' ');
2618 "Detected librtmp style URL parameters, these aren't supported "
2619 "by the libavformat internal RTMP handler currently enabled. "
2620 "See the documentation for the correct way to pass parameters.\n");
2625 char *ptr = strchr(auth,
':');
2633 if (rt->
listen && strcmp(proto,
"rtmp")) {
2638 if (!strcmp(proto,
"rtmpt") || !strcmp(proto,
"rtmpts")) {
2639 if (!strcmp(proto,
"rtmpts"))
2643 ff_url_join(buf,
sizeof(buf),
"ffrtmphttp", NULL, hostname, port, NULL);
2644 }
else if (!strcmp(proto,
"rtmps")) {
2648 ff_url_join(buf,
sizeof(buf),
"tls", NULL, hostname, port, NULL);
2649 }
else if (!strcmp(proto,
"rtmpe") || (!strcmp(proto,
"rtmpte"))) {
2650 if (!strcmp(proto,
"rtmpte"))
2651 av_dict_set(&opts,
"ffrtmpcrypt_tunneling",
"1", 1);
2654 ff_url_join(buf,
sizeof(buf),
"ffrtmpcrypt", NULL, hostname, port, NULL);
2661 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port,
2662 "?listen&listen_timeout=%d",
2665 ff_url_join(buf,
sizeof(buf),
"tcp", NULL, hostname, port, NULL);
2700 qmark = strchr(path,
'?');
2701 if (qmark && strstr(qmark,
"slist=")) {
2705 fname = strstr(path,
"slist=") + 6;
2707 amp = strchr(fname,
'&');
2710 sizeof(fname_buffer)));
2711 fname = fname_buffer;
2713 }
else if (!strncmp(path,
"/ondemand/", 10)) {
2715 memcpy(rt->
app,
"ondemand", 9);
2717 char *next = *path ? path + 1 : path;
2718 char *p = strchr(next,
'/');
2730 char *
c = strchr(p + 1,
':');
2731 fname = strchr(p + 1,
'/');
2732 if (!fname || (c && c < fname)) {
2760 int len = strlen(fname);
2761 if (!strchr(fname,
':') && len >= 4 &&
2762 (!strcmp(fname + len - 4,
".f4v") ||
2763 !strcmp(fname + len - 4,
".mp4"))) {
2766 if (len >= 4 && !strcmp(fname + len - 4,
".flv"))
2767 fname[len - 4] =
'\0';
2783 port,
"/%s", rt->
app);
2823 }
while (ret ==
AVERROR(EAGAIN));
2833 for (i = 0; i < 2; i++)
2895 int orig_size =
size;
2901 if (data_left >= size) {
2906 if (data_left > 0) {
2925 "Seek on stream index %d at timestamp %"PRId64
" with flags %08x\n",
2926 stream_index, timestamp, flags);
2927 if ((ret =
gen_seek(s, rt, timestamp)) < 0) {
2929 "Unable to send seek command on stream index %d at timestamp "
2930 "%"PRId64
" with flags %08x\n",
2931 stream_index, timestamp, flags);
2956 int size_temp =
size;
2957 int pktsize, pkttype,
copy;
2983 pkttype = bytestream_get_byte(&header);
2984 pktsize = bytestream_get_be24(&header);
2985 ts = bytestream_get_be24(&header);
2986 ts |= bytestream_get_byte(&header) << 24;
2987 bytestream_get_be24(&header);
3007 pkttype, ts, pktsize)) < 0)
3034 if (!strcmp(commandbuffer,
"onMetaData") ||
3035 !strcmp(commandbuffer,
"|RtmpSampleAccess")) {
3056 }
while (buf_temp - buf < size);
3074 }
else if (ret < 0) {
3076 }
else if (ret == 1) {
3094 #define OFFSET(x) offsetof(RTMPContext, x)
3095 #define DEC AV_OPT_FLAG_DECODING_PARAM
3096 #define ENC AV_OPT_FLAG_ENCODING_PARAM
3100 {
"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_flashver",
"Version of the Flash plugin used to run the SWF player.",
OFFSET(flashver),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC|
ENC},
3103 {
"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},
3104 {
"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"},
3108 {
"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},
3110 {
"rtmp_subscribe",
"Name of live stream to subscribe to. Defaults to rtmp_playpath.",
OFFSET(subscribe),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
3112 {
"rtmp_swfsize",
"Size of the decompressed SWF file, required for SWFVerification.",
OFFSET(swfsize),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC},
3114 {
"rtmp_swfverify",
"URL to player swf file, compute hash/size automatically.",
OFFSET(swfverify),
AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0,
DEC},
3115 {
"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},
3116 {
"rtmp_listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
3117 {
"listen",
"Listen for incoming rtmp connections",
OFFSET(listen),
AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX,
DEC,
"rtmp_listen" },
3118 {
"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" },
3122 #define RTMP_PROTOCOL(flavor) \
3123 static const AVClass flavor##_class = { \
3124 .class_name = #flavor, \
3125 .item_name = av_default_item_name, \
3126 .option = rtmp_options, \
3127 .version = LIBAVUTIL_VERSION_INT, \
3130 URLProtocol ff_##flavor##_protocol = { \
3132 .url_open = rtmp_open, \
3133 .url_read = rtmp_read, \
3134 .url_read_seek = rtmp_seek, \
3135 .url_read_pause = rtmp_pause, \
3136 .url_write = rtmp_write, \
3137 .url_close = rtmp_close, \
3138 .priv_data_size = sizeof(RTMPContext), \
3139 .flags = URL_PROTOCOL_FLAG_NETWORK, \
3140 .priv_data_class= &flavor##_class, \