#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
-int filter_nbthreads = -1;
-int filter_complex_nbthreads = -1;
-
static const enum AVPixelFormat *get_compliance_unofficial_pix_fmts(enum AVCodecID codec_id, const enum AVPixelFormat default_formats[])
{
static const enum AVPixelFormat mjpeg_formats[] =
fg->inputs[0]->graph = fg;
fg->inputs[0]->format = -1;
+ fg->inputs[0]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
+ if (!fg->inputs[0]->frame_queue)
+ exit_program(1);
+
GROW_ARRAY(ist->filters, ist->nb_filters);
ist->filters[ist->nb_filters - 1] = fg->inputs[0];
return 0;
}
+static char *describe_filter_link(FilterGraph *fg, AVFilterInOut *inout, int in)
+{
+ AVFilterContext *ctx = inout->filter_ctx;
+ AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads;
+ int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs;
+ AVIOContext *pb;
+ uint8_t *res = NULL;
+
+ if (avio_open_dyn_buf(&pb) < 0)
+ exit_program(1);
+
+ avio_printf(pb, "%s", ctx->filter->name);
+ if (nb_pads > 1)
+ avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));
+ avio_w8(pb, 0);
+ avio_close_dyn_buf(pb, &res);
+ return res;
+}
+
static void init_input_filter(FilterGraph *fg, AVFilterInOut *in)
{
InputStream *ist = NULL;
fg->inputs[fg->nb_inputs - 1]->ist = ist;
fg->inputs[fg->nb_inputs - 1]->graph = fg;
fg->inputs[fg->nb_inputs - 1]->format = -1;
+ fg->inputs[fg->nb_inputs - 1]->type = ist->st->codecpar->codec_type;
+ fg->inputs[fg->nb_inputs - 1]->name = describe_filter_link(fg, in, 1);
+
+ fg->inputs[fg->nb_inputs - 1]->frame_queue = av_fifo_alloc(8 * sizeof(AVFrame*));
+ if (!fg->inputs[fg->nb_inputs - 1]->frame_queue)
+ exit_program(1);
GROW_ARRAY(ist->filters, ist->nb_filters);
ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1];
fg->outputs[fg->nb_outputs - 1]->out_tmp = cur;
fg->outputs[fg->nb_outputs - 1]->type = avfilter_pad_get_type(cur->filter_ctx->output_pads,
cur->pad_idx);
+ fg->outputs[fg->nb_outputs - 1]->name = describe_filter_link(fg, cur, 0);
cur = cur->next;
fg->outputs[fg->nb_outputs - 1]->out_tmp->next = NULL;
}
int ret;
char name[255];
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("buffersink"),
name, NULL, NULL, fg->graph);
av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value);
}
- snprintf(name, sizeof(name), "scaler for output stream %d:%d",
+ snprintf(name, sizeof(name), "scaler_out_%d_%d",
ost->file_index, ost->index);
if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"),
name, args, NULL, fg->graph)) < 0)
if ((pix_fmts = choose_pix_fmts(ofilter))) {
AVFilterContext *filter;
- snprintf(name, sizeof(name), "pixel format for output stream %d:%d",
+ snprintf(name, sizeof(name), "format_out_%d_%d",
ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&filter,
avfilter_get_by_name("format"),
snprintf(args, sizeof(args), "fps=%d/%d", ost->frame_rate.num,
ost->frame_rate.den);
- snprintf(name, sizeof(name), "fps for output stream %d:%d",
+ snprintf(name, sizeof(name), "fps_out_%d_%d",
ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&fps, avfilter_get_by_name("fps"),
name, args, NULL, fg->graph);
pad_idx = 0;
}
- snprintf(name, sizeof(name), "trim for output stream %d:%d",
+ snprintf(name, sizeof(name), "trim_out_%d_%d",
ost->file_index, ost->index);
ret = insert_trim(of->start_time, of->recording_time,
&last_filter, &pad_idx, name);
char name[255];
int ret;
- snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index);
+ snprintf(name, sizeof(name), "out_%d_%d", ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&ofilter->filter,
avfilter_get_by_name("abuffersink"),
name, NULL, NULL, fg->graph);
av_freep(&sample_rates);
av_freep(&channel_layouts);
- snprintf(name, sizeof(name), "audio format for output stream %d:%d",
+ snprintf(name, sizeof(name), "format_out_%d_%d",
ost->file_index, ost->index);
ret = avfilter_graph_create_filter(&format,
avfilter_get_by_name("aformat"),
return 0;
}
-#define DESCRIBE_FILTER_LINK(f, inout, in) \
-{ \
- AVFilterContext *ctx = inout->filter_ctx; \
- AVFilterPad *pads = in ? ctx->input_pads : ctx->output_pads; \
- int nb_pads = in ? ctx->nb_inputs : ctx->nb_outputs; \
- AVIOContext *pb; \
- \
- if (avio_open_dyn_buf(&pb) < 0) \
- exit_program(1); \
- \
- avio_printf(pb, "%s", ctx->filter->name); \
- if (nb_pads > 1) \
- avio_printf(pb, ":%s", avfilter_pad_get_name(pads, inout->pad_idx));\
- avio_w8(pb, 0); \
- avio_close_dyn_buf(pb, &f->name); \
-}
-
int configure_output_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out)
{
- av_freep(&ofilter->name);
- DESCRIBE_FILTER_LINK(ofilter, out, 0);
-
if (!ofilter->ost) {
av_log(NULL, AV_LOG_FATAL, "Filter %s has an unconnected output\n", ofilter->name);
exit_program(1);
}
av_log(avf, AV_LOG_INFO, "sub2video: using %dx%d canvas\n", w, h);
}
- ist->sub2video.w = ist->resample_width = ifilter->width = w;
- ist->sub2video.h = ist->resample_height = ifilter->height = h;
+ ist->sub2video.w = ifilter->width = w;
+ ist->sub2video.h = ifilter->height = h;
+
+ ifilter->width = ist->dec_ctx->width ? ist->dec_ctx->width : ist->sub2video.w;
+ ifilter->height = ist->dec_ctx->height ? ist->dec_ctx->height : ist->sub2video.h;
/* rectangles are AV_PIX_FMT_PAL8, but we have no guarantee that the
palettes for all rectangles are identical or compatible */
- ist->resample_pix_fmt = ifilter->format = AV_PIX_FMT_RGB32;
+ ifilter->format = AV_PIX_FMT_RGB32;
ist->sub2video.frame = av_frame_alloc();
if (!ist->sub2video.frame)
return ret;
}
- if (ist->framerate.num) {
- AVFilterContext *setpts;
-
- snprintf(name, sizeof(name), "force CFR for input from stream %d:%d",
- ist->file_index, ist->st->index);
- if ((ret = avfilter_graph_create_filter(&setpts,
- avfilter_get_by_name("setpts"),
- name, "N", NULL,
- fg->graph)) < 0)
- return ret;
-
- if ((ret = avfilter_link(last_filter, 0, setpts, 0)) < 0)
- return ret;
-
- last_filter = setpts;
- }
-
if (do_deinterlace) {
AVFilterContext *yadif;
- snprintf(name, sizeof(name), "deinterlace input from stream %d:%d",
+ snprintf(name, sizeof(name), "deinterlace_in_%d_%d",
ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&yadif,
avfilter_get_by_name("yadif"),
last_filter = yadif;
}
- snprintf(name, sizeof(name), "trim for input stream %d:%d",
+ snprintf(name, sizeof(name), "trim_in_%d_%d",
ist->file_index, ist->st->index);
if (copy_ts) {
tsoffset = f->start_time == AV_NOPTS_VALUE ? 0 : f->start_time;
ifilter->channel_layout);
else
av_bprintf(&args, ":channels=%d", ifilter->channels);
- snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
+ snprintf(name, sizeof(name), "graph_%d_in_%d_%d", fg->index,
ist->file_index, ist->st->index);
if ((ret = avfilter_graph_create_filter(&ifilter->filter, abuffer_filt,
av_log(NULL, AV_LOG_INFO, opt_name " is forwarded to lavfi " \
"similarly to -af " filter_name "=%s.\n", arg); \
\
- snprintf(name, sizeof(name), "graph %d %s for input stream %d:%d", \
+ snprintf(name, sizeof(name), "graph_%d_%s_in_%d_%d", \
fg->index, filter_name, ist->file_index, ist->st->index); \
ret = avfilter_graph_create_filter(&filt_ctx, \
avfilter_get_by_name(filter_name), \
static int configure_input_filter(FilterGraph *fg, InputFilter *ifilter,
AVFilterInOut *in)
{
- av_freep(&ifilter->name);
- DESCRIBE_FILTER_LINK(ifilter, in, 1);
-
if (!ifilter->ist->dec) {
av_log(NULL, AV_LOG_ERROR,
"No decoder for stream #%d:%d, filtering impossible\n",
}
}
+static void cleanup_filtergraph(FilterGraph *fg)
+{
+ int i;
+ for (i = 0; i < fg->nb_outputs; i++)
+ fg->outputs[i]->filter = (AVFilterContext *)NULL;
+ for (i = 0; i < fg->nb_inputs; i++)
+ fg->inputs[i]->filter = (AVFilterContext *)NULL;
+ avfilter_graph_free(&fg->graph);
+}
+
int configure_filtergraph(FilterGraph *fg)
{
AVFilterInOut *inputs, *outputs, *cur;
const char *graph_desc = simple ? fg->outputs[0]->ost->avfilter :
fg->graph_desc;
- avfilter_graph_free(&fg->graph);
+ cleanup_filtergraph(fg);
if (!(fg->graph = avfilter_graph_alloc()))
return AVERROR(ENOMEM);
char args[512];
AVDictionaryEntry *e = NULL;
- fg->graph->nb_threads = filter_complex_nbthreads;
+ fg->graph->nb_threads = filter_nbthreads;
args[0] = 0;
while ((e = av_dict_get(ost->sws_dict, "", e,
if (e)
av_opt_set(fg->graph, "threads", e->value, 0);
} else {
- fg->graph->nb_threads = filter_nbthreads;
+ fg->graph->nb_threads = filter_complex_nbthreads;
}
if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0)
- return ret;
+ goto fail;
if (hw_device_ctx) {
for (i = 0; i < fg->graph->nb_filters; i++) {
" However, it had %s input(s) and %s output(s)."
" Please adjust, or use a complex filtergraph (-filter_complex) instead.\n",
graph_desc, num_inputs, num_outputs);
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
for (cur = inputs, i = 0; cur; cur = cur->next, i++)
if ((ret = configure_input_filter(fg, fg->inputs[i], cur)) < 0) {
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
- return ret;
+ goto fail;
}
avfilter_inout_free(&inputs);
avfilter_inout_free(&outputs);
if ((ret = avfilter_graph_config(fg->graph, NULL)) < 0)
- return ret;
+ goto fail;
/* limit the lists of allowed formats to the ones selected, to
* make sure they stay the same if the filtergraph is reconfigured later */
for (i = 0; i < fg->nb_outputs; i++) {
OutputFilter *ofilter = fg->outputs[i];
- AVFilterLink *link = ofilter->filter->inputs[0];
+ AVFilterContext *sink = ofilter->filter;
- ofilter->format = link->format;
+ ofilter->format = av_buffersink_get_format(sink);
- ofilter->width = link->w;
- ofilter->height = link->h;
+ ofilter->width = av_buffersink_get_w(sink);
+ ofilter->height = av_buffersink_get_h(sink);
- ofilter->sample_rate = link->sample_rate;
- ofilter->channel_layout = link->channel_layout;
+ ofilter->sample_rate = av_buffersink_get_sample_rate(sink);
+ ofilter->channel_layout = av_buffersink_get_channel_layout(sink);
}
fg->reconfiguration = 1;
complex filter graphs are initialized earlier */
av_log(NULL, AV_LOG_ERROR, "Encoder (codec %s) not found for output stream #%d:%d\n",
avcodec_get_name(ost->st->codecpar->codec_id), ost->file_index, ost->index);
- return AVERROR(EINVAL);
+ ret = AVERROR(EINVAL);
+ goto fail;
}
if (ost->enc->type == AVMEDIA_TYPE_AUDIO &&
!(ost->enc->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE))
ost->enc_ctx->frame_size);
}
+ for (i = 0; i < fg->nb_inputs; i++) {
+ while (av_fifo_size(fg->inputs[i]->frame_queue)) {
+ AVFrame *tmp;
+ av_fifo_generic_read(fg->inputs[i]->frame_queue, &tmp, sizeof(tmp), NULL);
+ ret = av_buffersrc_add_frame(fg->inputs[i]->filter, tmp);
+ av_frame_free(&tmp);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ /* send the EOFs for the finished inputs */
+ for (i = 0; i < fg->nb_inputs; i++) {
+ if (fg->inputs[i]->eof) {
+ ret = av_buffersrc_add_frame(fg->inputs[i]->filter, NULL);
+ if (ret < 0)
+ goto fail;
+ }
+ }
+
+ /* process queued up subtitle packets */
+ for (i = 0; i < fg->nb_inputs; i++) {
+ InputStream *ist = fg->inputs[i]->ist;
+ if (ist->sub2video.sub_queue && ist->sub2video.frame) {
+ while (av_fifo_size(ist->sub2video.sub_queue)) {
+ AVSubtitle tmp;
+ av_fifo_generic_read(ist->sub2video.sub_queue, &tmp, sizeof(tmp), NULL);
+ sub2video_update(ist, &tmp);
+ avsubtitle_free(&tmp);
+ }
+ }
+ }
+
return 0;
+
+fail:
+ cleanup_filtergraph(fg);
+ return ret;
}
int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame)
return 0;
}
-int ifilter_parameters_from_decoder(InputFilter *ifilter, const AVCodecContext *avctx)
-{
- av_buffer_unref(&ifilter->hw_frames_ctx);
-
- if (avctx->codec_type == AVMEDIA_TYPE_VIDEO)
- ifilter->format = avctx->pix_fmt;
- else
- ifilter->format = avctx->sample_fmt;
-
- ifilter->width = avctx->width;
- ifilter->height = avctx->height;
- if (ifilter->ist && ifilter->ist->st && ifilter->ist->st->sample_aspect_ratio.num)
- ifilter->sample_aspect_ratio = ifilter->ist->st->sample_aspect_ratio;
- else
- ifilter->sample_aspect_ratio = avctx->sample_aspect_ratio;
-
- ifilter->sample_rate = avctx->sample_rate;
- ifilter->channels = avctx->channels;
- ifilter->channel_layout = avctx->channel_layout;
-
- if (ifilter->ist && ifilter->ist->hw_frames_ctx) {
- ifilter->format = ifilter->ist->resample_pix_fmt;
- ifilter->hw_frames_ctx = av_buffer_ref(ifilter->ist->hw_frames_ctx);
- if (!ifilter->hw_frames_ctx)
- return AVERROR(ENOMEM);
- }
-
- return 0;
-}
-
int ist_in_filtergraph(FilterGraph *fg, InputStream *ist)
{
int i;