diff options
author | Vlad Tarca <vtarca@mobibase.com> | 2016-06-02 16:28:13 +0200 |
---|---|---|
committer | Michael Niedermayer <michael@niedermayer.cc> | 2016-11-13 11:38:15 +0100 |
commit | 2bd83ef26acf93fc818b1b75a5406dbfb196f6a4 (patch) | |
tree | 595d9fd09b5f97dfd9d13cd788a0161aecbf3cf0 /libavformat/rtpproto.c | |
parent | 183ce55b0de0a597b838d08bbac67f54c27ed42f (diff) | |
download | ffmpeg-2bd83ef26acf93fc818b1b75a5406dbfb196f6a4.tar.gz |
avformat: Add Pro-MPEG CoP #3-R2 FEC protocol
Pro-MPEG Code of Practice #3 release 2 forward error correction for rtp_mpegts streams
Signed-off-by: Vlad Tarca <vtarca@mobibase.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavformat/rtpproto.c')
-rw-r--r-- | libavformat/rtpproto.c | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index fa1dcb5570..840a36da00 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -44,7 +44,7 @@ typedef struct RTPContext { const AVClass *class; - URLContext *rtp_hd, *rtcp_hd; + URLContext *rtp_hd, *rtcp_hd, *fec_hd; int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs; struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; int write_to_source; @@ -58,6 +58,7 @@ typedef struct RTPContext { int dscp; char *sources; char *block; + char *fec_options_str; } RTPContext; #define OFFSET(x) offsetof(RTPContext, x) @@ -75,6 +76,7 @@ static const AVOption options[] = { { "dscp", "DSCP class", OFFSET(dscp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "sources", "Source list", OFFSET(sources), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, { "block", "Block list", OFFSET(block), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "fec", "FEC", OFFSET(fec_options_str), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = E }, { NULL } }; @@ -316,9 +318,11 @@ static void rtp_parse_addr_list(URLContext *h, char *buf, static int rtp_open(URLContext *h, const char *uri, int flags) { RTPContext *s = h->priv_data; + AVDictionary *fec_opts = NULL; int rtp_port; char hostname[256], include_sources[1024] = "", exclude_sources[1024] = ""; char *sources = include_sources, *block = exclude_sources; + char *fec_protocol = NULL; char buf[1024]; char path[1024]; const char *p; @@ -377,6 +381,31 @@ static int rtp_open(URLContext *h, const char *uri, int flags) } } + if (s->fec_options_str) { + p = s->fec_options_str; + + if (!(fec_protocol = av_get_token(&p, "="))) { + av_log(h, AV_LOG_ERROR, "Failed to parse the FEC protocol value\n"); + goto fail; + } + if (strcmp(fec_protocol, "prompeg")) { + av_log(h, AV_LOG_ERROR, "Unsupported FEC protocol %s\n", fec_protocol); + goto fail; + } + + p = s->fec_options_str + strlen(fec_protocol); + while (*p && *p == '=') p++; + + if (av_dict_parse_string(&fec_opts, p, "=", ":", 0) < 0) { + av_log(h, AV_LOG_ERROR, "Failed to parse the FEC options\n"); + goto fail; + } + if (s->ttl > 0) { + snprintf(buf, sizeof (buf), "%d", s->ttl); + av_dict_set(&fec_opts, "ttl", buf, 0); + } + } + for (i = 0; i < max_retry_count; i++) { build_udp_url(s, buf, sizeof(buf), hostname, rtp_port, s->local_rtpport, @@ -412,6 +441,14 @@ static int rtp_open(URLContext *h, const char *uri, int flags) break; } + s->fec_hd = NULL; + if (fec_protocol) { + ff_url_join(buf, sizeof(buf), fec_protocol, NULL, hostname, rtp_port, NULL); + if (ffurl_open_whitelist(&s->fec_hd, buf, flags, &h->interrupt_callback, + &fec_opts, h->protocol_whitelist, h->protocol_blacklist, h) < 0) + goto fail; + } + /* just to ease handle access. XXX: need to suppress direct handle access */ s->rtp_fd = ffurl_get_file_handle(s->rtp_hd); @@ -419,6 +456,10 @@ static int rtp_open(URLContext *h, const char *uri, int flags) h->max_packet_size = s->rtp_hd->max_packet_size; h->is_streamed = 1; + + av_free(fec_protocol); + av_dict_free(&fec_opts); + return 0; fail: @@ -426,6 +467,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ffurl_close(s->rtp_hd); if (s->rtcp_hd) ffurl_close(s->rtcp_hd); + ffurl_closep(&s->fec_hd); + av_free(fec_protocol); + av_dict_free(&fec_opts); return AVERROR(EIO); } @@ -474,7 +518,7 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) static int rtp_write(URLContext *h, const uint8_t *buf, int size) { RTPContext *s = h->priv_data; - int ret; + int ret, ret_fec; URLContext *hd; if (size < 2) @@ -543,7 +587,17 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) hd = s->rtp_hd; } - ret = ffurl_write(hd, buf, size); + if ((ret = ffurl_write(hd, buf, size)) < 0) { + return ret; + } + + if (s->fec_hd && !RTP_PT_IS_RTCP(buf[1])) { + if ((ret_fec = ffurl_write(s->fec_hd, buf, size)) < 0) { + av_log(h, AV_LOG_ERROR, "Failed to send FEC\n"); + return ret_fec; + } + } + return ret; } @@ -561,6 +615,7 @@ static int rtp_close(URLContext *h) ffurl_close(s->rtp_hd); ffurl_close(s->rtcp_hd); + ffurl_closep(&s->fec_hd); return 0; } |