| @@ -36,6 +36,7 @@ version <next>: | |||||
| - AAC encoding via libfdk-aac | - AAC encoding via libfdk-aac | ||||
| - Microsoft Expression Encoder Screen decoder | - Microsoft Expression Encoder Screen decoder | ||||
| - RTMPS protocol support | - RTMPS protocol support | ||||
| - RTMPTS protocol support | |||||
| version 0.8: | version 0.8: | ||||
| @@ -1547,6 +1547,8 @@ rtmps_protocol_deps="!librtmp_protocol" | |||||
| rtmps_protocol_select="tls_protocol" | rtmps_protocol_select="tls_protocol" | ||||
| rtmpt_protocol_deps="!librtmp_protocol" | rtmpt_protocol_deps="!librtmp_protocol" | ||||
| rtmpt_protocol_select="ffrtmphttp_protocol" | rtmpt_protocol_select="ffrtmphttp_protocol" | ||||
| rtmpts_protocol_deps="!librtmp_protocol" | |||||
| rtmpts_protocol_select="ffrtmphttp_protocol" | |||||
| rtp_protocol_select="udp_protocol" | rtp_protocol_select="udp_protocol" | ||||
| sctp_protocol_deps="network netinet_sctp_h" | sctp_protocol_deps="network netinet_sctp_h" | ||||
| tcp_protocol_deps="network" | tcp_protocol_deps="network" | ||||
| @@ -847,6 +847,7 @@ performance on systems without hardware floating point support). | |||||
| @item RTMPS @tab X | @item RTMPS @tab X | ||||
| @item RTMPT @tab X | @item RTMPT @tab X | ||||
| @item RTMPTE @tab E | @item RTMPTE @tab E | ||||
| @item RTMPTS @tab X | |||||
| @item RTP @tab X | @item RTP @tab X | ||||
| @item SCTP @tab X | @item SCTP @tab X | ||||
| @item TCP @tab X | @item TCP @tab X | ||||
| @@ -262,6 +262,14 @@ The Real-Time Messaging Protocol tunneled through HTTP (RTMPT) is used | |||||
| for streaming multimedia content within HTTP requests to traverse | for streaming multimedia content within HTTP requests to traverse | ||||
| firewalls. | firewalls. | ||||
| @section rtmpts | |||||
| Real-Time Messaging Protocol tunneled through HTTPS. | |||||
| The Real-Time Messaging Protocol tunneled through HTTPS (RTMPTS) is used | |||||
| for streaming multimedia content within HTTPS requests to traverse | |||||
| firewalls. | |||||
| @section rtmp, rtmpe, rtmps, rtmpt, rtmpte | @section rtmp, rtmpe, rtmps, rtmpt, rtmpte | ||||
| Real-Time Messaging Protocol and its variants supported through | Real-Time Messaging Protocol and its variants supported through | ||||
| @@ -354,6 +354,7 @@ OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o | |||||
| OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o | OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o | ||||
| OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o | OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o | ||||
| OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o | OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o | ||||
| OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o | |||||
| OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o | OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o | ||||
| OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o | OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o | ||||
| OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o | OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o | ||||
| @@ -260,6 +260,7 @@ void av_register_all(void) | |||||
| REGISTER_PROTOCOL (RTMP, rtmp); | REGISTER_PROTOCOL (RTMP, rtmp); | ||||
| REGISTER_PROTOCOL (RTMPS, rtmps); | REGISTER_PROTOCOL (RTMPS, rtmps); | ||||
| REGISTER_PROTOCOL (RTMPT, rtmpt); | REGISTER_PROTOCOL (RTMPT, rtmpt); | ||||
| REGISTER_PROTOCOL (RTMPTS, rtmpts); | |||||
| REGISTER_PROTOCOL (RTP, rtp); | REGISTER_PROTOCOL (RTP, rtp); | ||||
| REGISTER_PROTOCOL (SCTP, sctp); | REGISTER_PROTOCOL (SCTP, sctp); | ||||
| REGISTER_PROTOCOL (TCP, tcp); | REGISTER_PROTOCOL (TCP, tcp); | ||||
| @@ -30,11 +30,14 @@ | |||||
| #include "libavutil/time.h" | #include "libavutil/time.h" | ||||
| #include "internal.h" | #include "internal.h" | ||||
| #include "http.h" | #include "http.h" | ||||
| #include "rtmp.h" | |||||
| #define RTMPT_DEFAULT_PORT 80 | #define RTMPT_DEFAULT_PORT 80 | ||||
| #define RTMPTS_DEFAULT_PORT RTMPS_DEFAULT_PORT | |||||
| /* protocol handler context */ | /* protocol handler context */ | ||||
| typedef struct RTMP_HTTPContext { | typedef struct RTMP_HTTPContext { | ||||
| const AVClass *class; | |||||
| URLContext *stream; ///< HTTP stream | URLContext *stream; ///< HTTP stream | ||||
| char host[256]; ///< hostname of the server | char host[256]; ///< hostname of the server | ||||
| int port; ///< port to connect (default is 80) | int port; ///< port to connect (default is 80) | ||||
| @@ -46,6 +49,7 @@ typedef struct RTMP_HTTPContext { | |||||
| int initialized; ///< flag indicating when the http context is initialized | int initialized; ///< flag indicating when the http context is initialized | ||||
| int finishing; ///< flag indicating when the client closes the connection | int finishing; ///< flag indicating when the client closes the connection | ||||
| int nb_bytes_read; ///< number of bytes read since the last request | int nb_bytes_read; ///< number of bytes read since the last request | ||||
| int tls; ///< use Transport Security Layer (RTMPTS) | |||||
| } RTMP_HTTPContext; | } RTMP_HTTPContext; | ||||
| static int rtmp_http_send_cmd(URLContext *h, const char *cmd) | static int rtmp_http_send_cmd(URLContext *h, const char *cmd) | ||||
| @@ -185,9 +189,6 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags) | |||||
| av_url_split(NULL, 0, NULL, 0, rt->host, sizeof(rt->host), &rt->port, | av_url_split(NULL, 0, NULL, 0, rt->host, sizeof(rt->host), &rt->port, | ||||
| NULL, 0, uri); | NULL, 0, uri); | ||||
| if (rt->port < 0) | |||||
| rt->port = RTMPT_DEFAULT_PORT; | |||||
| /* This is the first request that is sent to the server in order to | /* This is the first request that is sent to the server in order to | ||||
| * register a client on the server and start a new session. The server | * register a client on the server and start a new session. The server | ||||
| * replies with a unique id (usually a number) that is used by the client | * replies with a unique id (usually a number) that is used by the client | ||||
| @@ -195,7 +196,15 @@ static int rtmp_http_open(URLContext *h, const char *uri, int flags) | |||||
| * Note: the reply doesn't contain a value for the polling interval. | * Note: the reply doesn't contain a value for the polling interval. | ||||
| * A successful connect resets the consecutive index that is used | * A successful connect resets the consecutive index that is used | ||||
| * in the URLs. */ | * in the URLs. */ | ||||
| ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1"); | |||||
| if (rt->tls) { | |||||
| if (rt->port < 0) | |||||
| rt->port = RTMPTS_DEFAULT_PORT; | |||||
| ff_url_join(url, sizeof(url), "https", NULL, rt->host, rt->port, "/open/1"); | |||||
| } else { | |||||
| if (rt->port < 0) | |||||
| rt->port = RTMPT_DEFAULT_PORT; | |||||
| ff_url_join(url, sizeof(url), "http", NULL, rt->host, rt->port, "/open/1"); | |||||
| } | |||||
| /* alloc the http context */ | /* alloc the http context */ | ||||
| if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0) | if ((ret = ffurl_alloc(&rt->stream, url, AVIO_FLAG_READ_WRITE, NULL)) < 0) | ||||
| @@ -240,6 +249,21 @@ fail: | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| #define OFFSET(x) offsetof(RTMP_HTTPContext, x) | |||||
| #define DEC AV_OPT_FLAG_DECODING_PARAM | |||||
| static const AVOption ffrtmphttp_options[] = { | |||||
| {"ffrtmphttp_tls", "Use a HTTPS tunneling connection (RTMPTS).", OFFSET(tls), AV_OPT_TYPE_INT, {0}, 0, 1, DEC}, | |||||
| { NULL }, | |||||
| }; | |||||
| static const AVClass ffrtmphttp_class = { | |||||
| .class_name = "ffrtmphttp", | |||||
| .item_name = av_default_item_name, | |||||
| .option = ffrtmphttp_options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| URLProtocol ff_ffrtmphttp_protocol = { | URLProtocol ff_ffrtmphttp_protocol = { | ||||
| .name = "ffrtmphttp", | .name = "ffrtmphttp", | ||||
| .url_open = rtmp_http_open, | .url_open = rtmp_http_open, | ||||
| @@ -248,4 +272,5 @@ URLProtocol ff_ffrtmphttp_protocol = { | |||||
| .url_close = rtmp_http_close, | .url_close = rtmp_http_close, | ||||
| .priv_data_size = sizeof(RTMP_HTTPContext), | .priv_data_size = sizeof(RTMP_HTTPContext), | ||||
| .flags = URL_PROTOCOL_FLAG_NETWORK, | .flags = URL_PROTOCOL_FLAG_NETWORK, | ||||
| .priv_data_class= &ffrtmphttp_class, | |||||
| }; | }; | ||||
| @@ -1111,6 +1111,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) | |||||
| char *old_app; | char *old_app; | ||||
| uint8_t buf[2048]; | uint8_t buf[2048]; | ||||
| int port; | int port; | ||||
| AVDictionary *opts = NULL; | |||||
| int ret; | int ret; | ||||
| rt->is_input = !(flags & AVIO_FLAG_WRITE); | rt->is_input = !(flags & AVIO_FLAG_WRITE); | ||||
| @@ -1118,7 +1119,10 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) | |||||
| av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, | av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, | ||||
| path, sizeof(path), s->filename); | path, sizeof(path), s->filename); | ||||
| if (!strcmp(proto, "rtmpt")) { | |||||
| if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) { | |||||
| if (!strcmp(proto, "rtmpts")) | |||||
| av_dict_set(&opts, "ffrtmphttp_tls", "1", 1); | |||||
| /* open the http tunneling connection */ | /* open the http tunneling connection */ | ||||
| ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL); | ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL); | ||||
| } else if (!strcmp(proto, "rtmps")) { | } else if (!strcmp(proto, "rtmps")) { | ||||
| @@ -1134,7 +1138,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) | |||||
| } | } | ||||
| if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE, | if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE, | ||||
| &s->interrupt_callback, NULL)) < 0) { | |||||
| &s->interrupt_callback, &opts)) < 0) { | |||||
| av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf); | av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf); | ||||
| goto fail; | goto fail; | ||||
| } | } | ||||
| @@ -1266,6 +1270,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) | |||||
| return 0; | return 0; | ||||
| fail: | fail: | ||||
| av_dict_free(&opts); | |||||
| rtmp_close(s); | rtmp_close(s); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -1484,3 +1489,21 @@ URLProtocol ff_rtmpt_protocol = { | |||||
| .flags = URL_PROTOCOL_FLAG_NETWORK, | .flags = URL_PROTOCOL_FLAG_NETWORK, | ||||
| .priv_data_class = &rtmpt_class, | .priv_data_class = &rtmpt_class, | ||||
| }; | }; | ||||
| static const AVClass rtmpts_class = { | |||||
| .class_name = "rtmpts", | |||||
| .item_name = av_default_item_name, | |||||
| .option = rtmp_options, | |||||
| .version = LIBAVUTIL_VERSION_INT, | |||||
| }; | |||||
| URLProtocol ff_rtmpts_protocol = { | |||||
| .name = "rtmpts", | |||||
| .url_open = rtmp_open, | |||||
| .url_read = rtmp_read, | |||||
| .url_write = rtmp_write, | |||||
| .url_close = rtmp_close, | |||||
| .priv_data_size = sizeof(RTMPContext), | |||||
| .flags = URL_PROTOCOL_FLAG_NETWORK, | |||||
| .priv_data_class = &rtmpts_class, | |||||
| }; | |||||
| @@ -30,7 +30,7 @@ | |||||
| #include "libavutil/avutil.h" | #include "libavutil/avutil.h" | ||||
| #define LIBAVFORMAT_VERSION_MAJOR 54 | #define LIBAVFORMAT_VERSION_MAJOR 54 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 8 | |||||
| #define LIBAVFORMAT_VERSION_MINOR 9 | |||||
| #define LIBAVFORMAT_VERSION_MICRO 0 | #define LIBAVFORMAT_VERSION_MICRO 0 | ||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||