* commit '2f3bada63e57345329c4f9b48e9b81b5cfc03d05': lavf: Add a protocol for SRTP encryption/decryption rtsp: Support decryption of SRTP signalled via RFC 4568 (SDES) Conflicts: libavformat/version.h Merged-by: Michael Niedermayer <michaelni@gmx.at>tags/n1.2
| @@ -3,6 +3,7 @@ releases are sorted from youngest to oldest. | |||
| version <next>: | |||
| - VDPAU hardware acceleration through normal hwaccel | |||
| - SRTP support | |||
| version 1.1: | |||
| @@ -43,7 +43,8 @@ OBJS-$(CONFIG_RTPDEC) += rdt.o \ | |||
| rtpdec_qt.o \ | |||
| rtpdec_svq3.o \ | |||
| rtpdec_vp8.o \ | |||
| rtpdec_xiph.o | |||
| rtpdec_xiph.o \ | |||
| srtp.o | |||
| OBJS-$(CONFIG_RTPENC_CHAIN) += rtpenc_chain.o rtp.o | |||
| # muxers/demuxers | |||
| @@ -430,6 +431,7 @@ OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o | |||
| OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o | |||
| OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o | |||
| OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o | |||
| OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o | |||
| OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o | |||
| OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o | |||
| OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o | |||
| @@ -327,6 +327,7 @@ void av_register_all(void) | |||
| REGISTER_PROTOCOL(RTMPTS, rtmpts); | |||
| REGISTER_PROTOCOL(RTP, rtp); | |||
| REGISTER_PROTOCOL(SCTP, sctp); | |||
| REGISTER_PROTOCOL(SRTP, srtp); | |||
| REGISTER_PROTOCOL(TCP, tcp); | |||
| REGISTER_PROTOCOL(TLS, tls); | |||
| REGISTER_PROTOCOL(UDP, udp); | |||
| @@ -26,6 +26,7 @@ | |||
| #include "avformat.h" | |||
| #include "mpegts.h" | |||
| #include "network.h" | |||
| #include "srtp.h" | |||
| #include "url.h" | |||
| #include "rtpdec.h" | |||
| #include "rtpdec_formats.h" | |||
| @@ -543,6 +544,13 @@ void ff_rtp_parse_set_dynamic_protocol(RTPDemuxContext *s, PayloadContext *ctx, | |||
| s->handler = handler; | |||
| } | |||
| void ff_rtp_parse_set_crypto(RTPDemuxContext *s, const char *suite, | |||
| const char *params) | |||
| { | |||
| if (!ff_srtp_set_crypto(&s->srtp, suite, params)) | |||
| s->srtp_enabled = 1; | |||
| } | |||
| /** | |||
| * This was the second switch in rtp_parse packet. | |||
| * Normalizes time, if required, sets stream_index, etc. | |||
| @@ -879,7 +887,10 @@ static int rtp_parse_one_packet(RTPDemuxContext *s, AVPacket *pkt, | |||
| int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, | |||
| uint8_t **bufptr, int len) | |||
| { | |||
| int rv = rtp_parse_one_packet(s, pkt, bufptr, len); | |||
| int rv; | |||
| if (s->srtp_enabled && bufptr && ff_srtp_decrypt(&s->srtp, *bufptr, &len) < 0) | |||
| return -1; | |||
| rv = rtp_parse_one_packet(s, pkt, bufptr, len); | |||
| s->prev_ret = rv; | |||
| while (rv == AVERROR(EAGAIN) && has_next_packet(s)) | |||
| rv = rtp_parse_queued_packet(s, pkt); | |||
| @@ -892,6 +903,7 @@ void ff_rtp_parse_close(RTPDemuxContext *s) | |||
| if (!strcmp(ff_rtp_enc_name(s->payload_type), "MP2T")) { | |||
| ff_mpegts_parse_close(s->ts); | |||
| } | |||
| ff_srtp_free(&s->srtp); | |||
| av_free(s); | |||
| } | |||
| @@ -27,6 +27,7 @@ | |||
| #include "avformat.h" | |||
| #include "rtp.h" | |||
| #include "url.h" | |||
| #include "srtp.h" | |||
| typedef struct PayloadContext PayloadContext; | |||
| typedef struct RTPDynamicProtocolHandler RTPDynamicProtocolHandler; | |||
| @@ -43,6 +44,8 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, | |||
| int payload_type, int queue_size); | |||
| void ff_rtp_parse_set_dynamic_protocol(RTPDemuxContext *s, PayloadContext *ctx, | |||
| RTPDynamicProtocolHandler *handler); | |||
| void ff_rtp_parse_set_crypto(RTPDemuxContext *s, const char *suite, | |||
| const char *params); | |||
| int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, | |||
| uint8_t **buf, int len); | |||
| void ff_rtp_parse_close(RTPDemuxContext *s); | |||
| @@ -163,6 +166,9 @@ struct RTPDemuxContext { | |||
| /* used to send back RTCP RR */ | |||
| char hostname[256]; | |||
| int srtp_enabled; | |||
| struct SRTPContext srtp; | |||
| /** Statistics for this stream (used by RTCP receiver reports) */ | |||
| RTPStatistics statistics; | |||
| @@ -480,6 +480,14 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, | |||
| s->nb_streams > 0) { | |||
| st = s->streams[s->nb_streams - 1]; | |||
| st->codec->sample_rate = atoi(p); | |||
| } else if (av_strstart(p, "crypto:", &p) && s->nb_streams > 0) { | |||
| // RFC 4568 | |||
| rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; | |||
| get_word(buf1, sizeof(buf1), &p); // ignore tag | |||
| get_word(rtsp_st->crypto_suite, sizeof(rtsp_st->crypto_suite), &p); | |||
| p += strspn(p, SPACE_CHARS); | |||
| if (av_strstart(p, "inline:", &p)) | |||
| get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p); | |||
| } else { | |||
| if (rt->server_type == RTSP_SERVER_WMS) | |||
| ff_wms_parse_sdp_a_line(s, p); | |||
| @@ -653,6 +661,10 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) | |||
| rtsp_st->dynamic_protocol_context, | |||
| rtsp_st->dynamic_handler); | |||
| } | |||
| if (rtsp_st->crypto_suite[0]) | |||
| ff_rtp_parse_set_crypto(rtsp_st->transport_priv, | |||
| rtsp_st->crypto_suite, | |||
| rtsp_st->crypto_params); | |||
| } | |||
| return 0; | |||
| @@ -440,6 +440,9 @@ typedef struct RTSPStream { | |||
| /** Enable sending RTCP feedback messages according to RFC 4585 */ | |||
| int feedback; | |||
| char crypto_suite[40]; | |||
| char crypto_params[100]; | |||
| } RTSPStream; | |||
| void ff_rtsp_parse_line(RTSPMessageHeader *reply, const char *buf, | |||
| @@ -0,0 +1,144 @@ | |||
| /* | |||
| * SRTP network protocol | |||
| * Copyright (c) 2012 Martin Storsjo | |||
| * | |||
| * This file is part of FFmpeg. | |||
| * | |||
| * FFmpeg is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * FFmpeg is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with FFmpeg; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #include "libavutil/opt.h" | |||
| #include "avformat.h" | |||
| #include "avio_internal.h" | |||
| #include "url.h" | |||
| #include "internal.h" | |||
| #include "srtp.h" | |||
| typedef struct SRTPProtoContext { | |||
| const AVClass *class; | |||
| URLContext *rtp_hd; | |||
| const char *out_suite, *out_params; | |||
| const char *in_suite, *in_params; | |||
| struct SRTPContext srtp_out, srtp_in; | |||
| uint8_t encryptbuf[1500]; | |||
| } SRTPProtoContext; | |||
| #define D AV_OPT_FLAG_DECODING_PARAM | |||
| #define E AV_OPT_FLAG_ENCODING_PARAM | |||
| static const AVOption options[] = { | |||
| { "srtp_out_suite", "", offsetof(SRTPProtoContext, out_suite), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, | |||
| { "srtp_out_params", "", offsetof(SRTPProtoContext, out_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, | |||
| { "srtp_in_suite", "", offsetof(SRTPProtoContext, in_suite), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, | |||
| { "srtp_in_params", "", offsetof(SRTPProtoContext, in_params), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, | |||
| { NULL } | |||
| }; | |||
| static const AVClass srtp_context_class = { | |||
| .class_name = "srtp", | |||
| .item_name = av_default_item_name, | |||
| .option = options, | |||
| .version = LIBAVUTIL_VERSION_INT, | |||
| }; | |||
| static int srtp_close(URLContext *h) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| ff_srtp_free(&s->srtp_out); | |||
| ff_srtp_free(&s->srtp_in); | |||
| ffurl_close(s->rtp_hd); | |||
| s->rtp_hd = NULL; | |||
| return 0; | |||
| } | |||
| static int srtp_open(URLContext *h, const char *uri, int flags) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| char hostname[256], buf[1024], path[1024]; | |||
| int rtp_port, ret; | |||
| if (s->out_suite && s->out_params) | |||
| if ((ret = ff_srtp_set_crypto(&s->srtp_out, s->out_suite, s->out_params)) < 0) | |||
| goto fail; | |||
| if (s->in_suite && s->in_params) | |||
| if ((ret = ff_srtp_set_crypto(&s->srtp_in, s->in_suite, s->in_params)) < 0) | |||
| goto fail; | |||
| av_url_split(NULL, 0, NULL, 0, hostname, sizeof(hostname), &rtp_port, | |||
| path, sizeof(path), uri); | |||
| ff_url_join(buf, sizeof(buf), "rtp", NULL, hostname, rtp_port, "%s", path); | |||
| if ((ret = ffurl_open(&s->rtp_hd, buf, flags, &h->interrupt_callback, NULL)) < 0) | |||
| goto fail; | |||
| h->max_packet_size = FFMIN(s->rtp_hd->max_packet_size, | |||
| sizeof(s->encryptbuf)) - 14; | |||
| h->is_streamed = 1; | |||
| return 0; | |||
| fail: | |||
| srtp_close(h); | |||
| return ret; | |||
| } | |||
| static int srtp_read(URLContext *h, uint8_t *buf, int size) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| int ret; | |||
| start: | |||
| ret = ffurl_read(s->rtp_hd, buf, size); | |||
| if (ret > 0 && s->srtp_in.aes) { | |||
| if (ff_srtp_decrypt(&s->srtp_in, buf, &ret) < 0) | |||
| goto start; | |||
| } | |||
| return ret; | |||
| } | |||
| static int srtp_write(URLContext *h, const uint8_t *buf, int size) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| if (!s->srtp_out.aes) | |||
| return ffurl_write(s->rtp_hd, buf, size); | |||
| size = ff_srtp_encrypt(&s->srtp_out, buf, size, s->encryptbuf, | |||
| sizeof(s->encryptbuf)); | |||
| if (size < 0) | |||
| return size; | |||
| return ffurl_write(s->rtp_hd, s->encryptbuf, size); | |||
| } | |||
| static int srtp_get_file_handle(URLContext *h) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| return ffurl_get_file_handle(s->rtp_hd); | |||
| } | |||
| static int srtp_get_multi_file_handle(URLContext *h, int **handles, | |||
| int *numhandles) | |||
| { | |||
| SRTPProtoContext *s = h->priv_data; | |||
| return ffurl_get_multi_file_handle(s->rtp_hd, handles, numhandles); | |||
| } | |||
| URLProtocol ff_srtp_protocol = { | |||
| .name = "srtp", | |||
| .url_open = srtp_open, | |||
| .url_read = srtp_read, | |||
| .url_write = srtp_write, | |||
| .url_close = srtp_close, | |||
| .url_get_file_handle = srtp_get_file_handle, | |||
| .url_get_multi_file_handle = srtp_get_multi_file_handle, | |||
| .priv_data_size = sizeof(SRTPProtoContext), | |||
| .priv_data_class = &srtp_context_class, | |||
| .flags = URL_PROTOCOL_FLAG_NETWORK, | |||
| }; | |||
| @@ -30,8 +30,8 @@ | |||
| #include "libavutil/avutil.h" | |||
| #define LIBAVFORMAT_VERSION_MAJOR 54 | |||
| #define LIBAVFORMAT_VERSION_MINOR 59 | |||
| #define LIBAVFORMAT_VERSION_MICRO 107 | |||
| #define LIBAVFORMAT_VERSION_MINOR 60 | |||
| #define LIBAVFORMAT_VERSION_MICRO 100 | |||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | |||
| LIBAVFORMAT_VERSION_MINOR, \ | |||