Commit 2bd83ef2 authored by Vlad Tarca's avatar Vlad Tarca Committed by Michael Niedermayer

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: 's avatarVlad Tarca <vtarca@mobibase.com>
Signed-off-by: 's avatarMichael Niedermayer <michael@niedermayer.cc>
parent 183ce55b
...@@ -4,6 +4,7 @@ releases are sorted from youngest to oldest. ...@@ -4,6 +4,7 @@ releases are sorted from youngest to oldest.
version <next>: version <next>:
- CrystalHD decoder moved to new decode API - CrystalHD decoder moved to new decode API
- add internal ebur128 library, remove external libebur128 dependency - add internal ebur128 library, remove external libebur128 dependency
- Pro-MPEG CoP #3-R2 FEC protocol
version 3.2: version 3.2:
- libopenmpt demuxer - libopenmpt demuxer
......
...@@ -1137,6 +1137,7 @@ performance on systems without hardware floating point support). ...@@ -1137,6 +1137,7 @@ performance on systems without hardware floating point support).
@item MMSH @tab X @item MMSH @tab X
@item MMST @tab X @item MMST @tab X
@item pipe @tab X @item pipe @tab X
@item Pro-MPEG FEC @tab X
@item RTMP @tab X @item RTMP @tab X
@item RTMPE @tab X @item RTMPE @tab X
@item RTMPS @tab X @item RTMPS @tab X
......
...@@ -515,6 +515,41 @@ time, which is valuable if data transmission is slow. ...@@ -515,6 +515,41 @@ time, which is valuable if data transmission is slow.
Note that some formats (typically MOV), require the output protocol to Note that some formats (typically MOV), require the output protocol to
be seekable, so they will fail with the pipe output protocol. be seekable, so they will fail with the pipe output protocol.
@section prompeg
Pro-MPEG Code of Practice #3 Release 2 FEC protocol.
The Pro-MPEG CoP#3 FEC is a 2D parity-check forward error correction mechanism
for MPEG-2 Transport Streams sent over RTP.
This protocol must be used in conjunction with the @code{rtp_mpegts} muxer and
the @code{rtp} protocol.
The required syntax is:
@example
-f rtp_mpegts -fec prompeg=@var{option}=@var{val}... rtp://@var{hostname}:@var{port}
@end example
The destination UDP ports are @code{port + 2} for the column FEC stream
and @code{port + 4} for the row FEC stream.
This protocol accepts the following options:
@table @option
@item l=@var{n}
The number of columns (4-20, LxD <= 100)
@item d=@var{n}
The number of rows (4-20, LxD <= 100)
@end table
Example usage:
@example
-f rtp_mpegts -fec prompeg=l=8:d=4 rtp://@var{hostname}:@var{port}
@end example
@section rtmp @section rtmp
Real-Time Messaging Protocol. Real-Time Messaging Protocol.
......
...@@ -558,6 +558,7 @@ OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o ...@@ -558,6 +558,7 @@ OBJS-$(CONFIG_MD5_PROTOCOL) += md5proto.o
OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o
OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o
OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o
OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o
OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o
OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o
......
This diff is collapsed.
...@@ -43,6 +43,7 @@ extern const URLProtocol ff_mmsh_protocol; ...@@ -43,6 +43,7 @@ extern const URLProtocol ff_mmsh_protocol;
extern const URLProtocol ff_mmst_protocol; extern const URLProtocol ff_mmst_protocol;
extern const URLProtocol ff_md5_protocol; extern const URLProtocol ff_md5_protocol;
extern const URLProtocol ff_pipe_protocol; extern const URLProtocol ff_pipe_protocol;
extern const URLProtocol ff_prompeg_protocol;
extern const URLProtocol ff_rtmp_protocol; extern const URLProtocol ff_rtmp_protocol;
extern const URLProtocol ff_rtmpe_protocol; extern const URLProtocol ff_rtmpe_protocol;
extern const URLProtocol ff_rtmps_protocol; extern const URLProtocol ff_rtmps_protocol;
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
typedef struct RTPContext { typedef struct RTPContext {
const AVClass *class; 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; int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs;
struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs;
int write_to_source; int write_to_source;
...@@ -58,6 +58,7 @@ typedef struct RTPContext { ...@@ -58,6 +58,7 @@ typedef struct RTPContext {
int dscp; int dscp;
char *sources; char *sources;
char *block; char *block;
char *fec_options_str;
} RTPContext; } RTPContext;
#define OFFSET(x) offsetof(RTPContext, x) #define OFFSET(x) offsetof(RTPContext, x)
...@@ -75,6 +76,7 @@ static const AVOption options[] = { ...@@ -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 }, { "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 }, { "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 }, { "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 } { NULL }
}; };
...@@ -316,9 +318,11 @@ static void rtp_parse_addr_list(URLContext *h, char *buf, ...@@ -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) static int rtp_open(URLContext *h, const char *uri, int flags)
{ {
RTPContext *s = h->priv_data; RTPContext *s = h->priv_data;
AVDictionary *fec_opts = NULL;
int rtp_port; int rtp_port;
char hostname[256], include_sources[1024] = "", exclude_sources[1024] = ""; char hostname[256], include_sources[1024] = "", exclude_sources[1024] = "";
char *sources = include_sources, *block = exclude_sources; char *sources = include_sources, *block = exclude_sources;
char *fec_protocol = NULL;
char buf[1024]; char buf[1024];
char path[1024]; char path[1024];
const char *p; const char *p;
...@@ -377,6 +381,31 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ...@@ -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++) { for (i = 0; i < max_retry_count; i++) {
build_udp_url(s, buf, sizeof(buf), build_udp_url(s, buf, sizeof(buf),
hostname, rtp_port, s->local_rtpport, hostname, rtp_port, s->local_rtpport,
...@@ -412,6 +441,14 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ...@@ -412,6 +441,14 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
break; 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 /* just to ease handle access. XXX: need to suppress direct handle
access */ access */
s->rtp_fd = ffurl_get_file_handle(s->rtp_hd); 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) ...@@ -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->max_packet_size = s->rtp_hd->max_packet_size;
h->is_streamed = 1; h->is_streamed = 1;
av_free(fec_protocol);
av_dict_free(&fec_opts);
return 0; return 0;
fail: fail:
...@@ -426,6 +467,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags) ...@@ -426,6 +467,9 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
ffurl_close(s->rtp_hd); ffurl_close(s->rtp_hd);
if (s->rtcp_hd) if (s->rtcp_hd)
ffurl_close(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); return AVERROR(EIO);
} }
...@@ -474,7 +518,7 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) ...@@ -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) static int rtp_write(URLContext *h, const uint8_t *buf, int size)
{ {
RTPContext *s = h->priv_data; RTPContext *s = h->priv_data;
int ret; int ret, ret_fec;
URLContext *hd; URLContext *hd;
if (size < 2) if (size < 2)
...@@ -543,7 +587,17 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) ...@@ -543,7 +587,17 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size)
hd = s->rtp_hd; 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; return ret;
} }
...@@ -561,6 +615,7 @@ static int rtp_close(URLContext *h) ...@@ -561,6 +615,7 @@ static int rtp_close(URLContext *h)
ffurl_close(s->rtp_hd); ffurl_close(s->rtp_hd);
ffurl_close(s->rtcp_hd); ffurl_close(s->rtcp_hd);
ffurl_closep(&s->fec_hd);
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment