AVBSFContext **bsfs; ///< bitstream filters per stream
SlaveFailurePolicy on_fail;
+ int use_fifo;
+ AVDictionary *fifo_options;
/** map from input to output streams indexes,
* disabled output streams are set to -1 */
unsigned nb_slaves;
unsigned nb_alive;
TeeSlave *slaves;
+ int use_fifo;
+ AVDictionary *fifo_options;
+ char *fifo_options_str;
} TeeContext;
static const char *const slave_delim = "|";
static const char *const slave_bsfs_spec_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 = {
.class_name = "Tee muxer",
.item_name = av_default_item_name,
+ .option = options,
.version = LIBAVUTIL_VERSION_INT,
};
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)
{
AVFormatContext *avf;
AVDictionaryEntry *entry;
char *filename;
char *format = NULL, *select = NULL, *on_fail = NULL;
+ char *use_fifo = NULL, *fifo_options_str = NULL;
AVFormatContext *avf2 = NULL;
AVStream *st, *st2;
int stream_count;
STEAL_OPTION("f", format);
STEAL_OPTION("select", select);
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);
if (ret < 0) {
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_opts", 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)
goto end;
tee_slave->avf = avf2;
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)))) {
ret = AVERROR(ENOMEM);
goto fail;
tee->nb_slaves = tee->nb_alive = nb_slaves;
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) {
ret = tee_process_slave_failure(avf, i, ret);
if (ret < 0)