mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
libavformat/tee: Add fifo support for tee
Signed-off-by: Jan Sebechlebsky <sebechlebskyjan@gmail.com>
This commit is contained in:
parent
616513ef6e
commit
7c91ee01cc
@ -1494,6 +1494,7 @@ Specify whether to remove all fragments when finished. Default 0 (do not remove)
|
|||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@anchor{fifo}
|
||||||
@section fifo
|
@section fifo
|
||||||
|
|
||||||
The fifo pseudo-muxer allows the separation of encoding and muxing by using
|
The fifo pseudo-muxer allows the separation of encoding and muxing by using
|
||||||
@ -1601,6 +1602,18 @@ with the tee muxer; encoding can be a very expensive process. It is not
|
|||||||
useful when using the libavformat API directly because it is then possible
|
useful when using the libavformat API directly because it is then possible
|
||||||
to feed the same packets to several muxers directly.
|
to feed the same packets to several muxers directly.
|
||||||
|
|
||||||
|
@table @option
|
||||||
|
|
||||||
|
@item use_fifo @var{bool}
|
||||||
|
If set to 1, slave outputs will be processed in separate thread using @ref{fifo}
|
||||||
|
muxer. This allows to compensate for different speed/latency/reliability of
|
||||||
|
outputs and setup transparent recovery. By default this feature is turned off.
|
||||||
|
|
||||||
|
@item fifo_options
|
||||||
|
Options to pass to fifo pseudo-muxer instances. See @ref{fifo}.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
The slave outputs are specified in the file name given to the muxer,
|
The slave outputs are specified in the file name given to the muxer,
|
||||||
separated by '|'. If any of the slave name contains the '|' separator,
|
separated by '|'. If any of the slave name contains the '|' separator,
|
||||||
leading or trailing spaces or any special character, it must be
|
leading or trailing spaces or any special character, it must be
|
||||||
@ -1622,6 +1635,13 @@ output name suffix.
|
|||||||
Specify a list of bitstream filters to apply to the specified
|
Specify a list of bitstream filters to apply to the specified
|
||||||
output.
|
output.
|
||||||
|
|
||||||
|
@item use_fifo @var{bool}
|
||||||
|
This allows to override tee muxer use_fifo option for individual slave muxer.
|
||||||
|
|
||||||
|
@item fifo_options
|
||||||
|
This allows to override tee muxer fifo_options for individual slave muxer.
|
||||||
|
See @ref{fifo}.
|
||||||
|
|
||||||
It is possible to specify to which streams a given bitstream filter
|
It is possible to specify to which streams a given bitstream filter
|
||||||
applies, by appending a stream specifier to the option separated by
|
applies, by appending a stream specifier to the option separated by
|
||||||
@code{/}. @var{spec} must be a stream specifier (see @ref{Format
|
@code{/}. @var{spec} must be a stream specifier (see @ref{Format
|
||||||
|
@ -40,6 +40,8 @@ typedef struct {
|
|||||||
AVBSFContext **bsfs; ///< bitstream filters per stream
|
AVBSFContext **bsfs; ///< bitstream filters per stream
|
||||||
|
|
||||||
SlaveFailurePolicy on_fail;
|
SlaveFailurePolicy on_fail;
|
||||||
|
int use_fifo;
|
||||||
|
AVDictionary *fifo_options;
|
||||||
|
|
||||||
/** map from input to output streams indexes,
|
/** map from input to output streams indexes,
|
||||||
* disabled output streams are set to -1 */
|
* disabled output streams are set to -1 */
|
||||||
@ -52,15 +54,28 @@ typedef struct TeeContext {
|
|||||||
unsigned nb_slaves;
|
unsigned nb_slaves;
|
||||||
unsigned nb_alive;
|
unsigned nb_alive;
|
||||||
TeeSlave *slaves;
|
TeeSlave *slaves;
|
||||||
|
int use_fifo;
|
||||||
|
AVDictionary *fifo_options;
|
||||||
|
char *fifo_options_str;
|
||||||
} TeeContext;
|
} TeeContext;
|
||||||
|
|
||||||
static const char *const slave_delim = "|";
|
static const char *const slave_delim = "|";
|
||||||
static const char *const slave_bsfs_spec_sep = "/";
|
static const char *const slave_bsfs_spec_sep = "/";
|
||||||
static const char *const slave_select_sep = ",";
|
static const char *const slave_select_sep = ",";
|
||||||
|
|
||||||
|
#define OFFSET(x) offsetof(TeeContext, x)
|
||||||
|
static const AVOption options[] = {
|
||||||
|
{"use_fifo", "Use fifo pseudo-muxer to separate actual muxers from encoder",
|
||||||
|
OFFSET(use_fifo), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
|
||||||
|
{"fifo_options", "fifo pseudo-muxer options", OFFSET(fifo_options_str),
|
||||||
|
AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM},
|
||||||
|
{NULL}
|
||||||
|
};
|
||||||
|
|
||||||
static const AVClass tee_muxer_class = {
|
static const AVClass tee_muxer_class = {
|
||||||
.class_name = "Tee muxer",
|
.class_name = "Tee muxer",
|
||||||
.item_name = av_default_item_name,
|
.item_name = av_default_item_name,
|
||||||
|
.option = options,
|
||||||
.version = LIBAVUTIL_VERSION_INT,
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -81,6 +96,29 @@ static inline int parse_slave_failure_policy_option(const char *opt, TeeSlave *t
|
|||||||
return AVERROR(EINVAL);
|
return AVERROR(EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_slave_fifo_options(const char *use_fifo,
|
||||||
|
const char *fifo_options, TeeSlave *tee_slave)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (use_fifo) {
|
||||||
|
/*TODO - change this to use proper function for parsing boolean
|
||||||
|
* options when there is one */
|
||||||
|
if (av_match_name(use_fifo, "true,y,yes,enable,enabled,on,1")) {
|
||||||
|
tee_slave->use_fifo = 1;
|
||||||
|
} else if (av_match_name(use_fifo, "false,n,no,disable,disabled,off,0")) {
|
||||||
|
tee_slave->use_fifo = 0;
|
||||||
|
} else {
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifo_options)
|
||||||
|
ret = av_dict_parse_string(&tee_slave->fifo_options, fifo_options, "=", ":", 0);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int close_slave(TeeSlave *tee_slave)
|
static int close_slave(TeeSlave *tee_slave)
|
||||||
{
|
{
|
||||||
AVFormatContext *avf;
|
AVFormatContext *avf;
|
||||||
@ -125,6 +163,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
|
|||||||
AVDictionaryEntry *entry;
|
AVDictionaryEntry *entry;
|
||||||
char *filename;
|
char *filename;
|
||||||
char *format = NULL, *select = NULL, *on_fail = NULL;
|
char *format = NULL, *select = NULL, *on_fail = NULL;
|
||||||
|
char *use_fifo = NULL, *fifo_options_str = NULL;
|
||||||
AVFormatContext *avf2 = NULL;
|
AVFormatContext *avf2 = NULL;
|
||||||
AVStream *st, *st2;
|
AVStream *st, *st2;
|
||||||
int stream_count;
|
int stream_count;
|
||||||
@ -145,6 +184,8 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
|
|||||||
STEAL_OPTION("f", format);
|
STEAL_OPTION("f", format);
|
||||||
STEAL_OPTION("select", select);
|
STEAL_OPTION("select", select);
|
||||||
STEAL_OPTION("onfail", on_fail);
|
STEAL_OPTION("onfail", on_fail);
|
||||||
|
STEAL_OPTION("use_fifo", use_fifo);
|
||||||
|
STEAL_OPTION("fifo_options", fifo_options_str);
|
||||||
|
|
||||||
ret = parse_slave_failure_policy_option(on_fail, tee_slave);
|
ret = parse_slave_failure_policy_option(on_fail, tee_slave);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -153,7 +194,39 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = avformat_alloc_output_context2(&avf2, NULL, format, filename);
|
ret = parse_slave_fifo_options(use_fifo, fifo_options_str, tee_slave);
|
||||||
|
if (ret < 0) {
|
||||||
|
av_log(avf, AV_LOG_ERROR, "Error parsing fifo options: %s\n", av_err2str(ret));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tee_slave->use_fifo) {
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
char *format_options_str = NULL;
|
||||||
|
ret = av_dict_get_string(options, &format_options_str, '=', ':');
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
ret = av_dict_set(&tee_slave->fifo_options, "format_options", format_options_str,
|
||||||
|
AV_DICT_DONT_STRDUP_VAL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format) {
|
||||||
|
ret = av_dict_set(&tee_slave->fifo_options, "fifo_format", format,
|
||||||
|
AV_DICT_DONT_STRDUP_VAL);
|
||||||
|
format = NULL;
|
||||||
|
if (ret < 0)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_dict_free(&options);
|
||||||
|
options = tee_slave->fifo_options;
|
||||||
|
}
|
||||||
|
ret = avformat_alloc_output_context2(&avf2, NULL,
|
||||||
|
tee_slave->use_fifo ? "fifo" :format, filename);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto end;
|
goto end;
|
||||||
tee_slave->avf = avf2;
|
tee_slave->avf = avf2;
|
||||||
@ -394,6 +467,12 @@ static int tee_write_header(AVFormatContext *avf)
|
|||||||
filename++;
|
filename++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tee->fifo_options_str) {
|
||||||
|
ret = av_dict_parse_string(&tee->fifo_options, tee->fifo_options_str, "=", ":", 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) {
|
if (!(tee->slaves = av_mallocz_array(nb_slaves, sizeof(*tee->slaves)))) {
|
||||||
ret = AVERROR(ENOMEM);
|
ret = AVERROR(ENOMEM);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -401,6 +480,12 @@ static int tee_write_header(AVFormatContext *avf)
|
|||||||
tee->nb_slaves = tee->nb_alive = nb_slaves;
|
tee->nb_slaves = tee->nb_alive = nb_slaves;
|
||||||
|
|
||||||
for (i = 0; i < nb_slaves; i++) {
|
for (i = 0; i < nb_slaves; i++) {
|
||||||
|
|
||||||
|
tee->slaves[i].use_fifo = tee->use_fifo;
|
||||||
|
ret = av_dict_copy(&tee->slaves[i].fifo_options, tee->fifo_options, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
|
if ((ret = open_slave(avf, slaves[i], &tee->slaves[i])) < 0) {
|
||||||
ret = tee_process_slave_failure(avf, i, ret);
|
ret = tee_process_slave_failure(avf, i, ret);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user