X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=avconv_filter.c;h=1d8044d70b53c28ffea66d20d15896c672ad2e63;hb=42b9150b0d4f0a130c1d93dc991fd5412743a8cf;hp=4e5c1ecb03272c0805c8ecaa68c22d556fd95372;hpb=a3ad68d36c0bff87c525035b3f745bb274b00d41;p=ffmpeg diff --git a/avconv_filter.c b/avconv_filter.c index 4e5c1ecb032..1d8044d70b5 100644 --- a/avconv_filter.c +++ b/avconv_filter.c @@ -21,36 +21,37 @@ #include "avconv.h" #include "libavfilter/avfilter.h" -#include "libavfilter/avfiltergraph.h" -#include "libavutil/audioconvert.h" +#include "libavresample/avresample.h" + #include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "libavutil/samplefmt.h" -/** - * Define a function for building a string containing a list of - * allowed formats, - */ -#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name, separator)\ +/* Define a function for building a string containing a list of + * allowed formats. */ +#define DEF_CHOOSE_FORMAT(type, var, supported_list, none, get_name) \ static char *choose_ ## var ## s(OutputStream *ost) \ { \ if (ost->st->codec->var != none) { \ get_name(ost->st->codec->var); \ return av_strdup(name); \ - } else if (ost->enc->supported_list) { \ + } else if (ost->enc && ost->enc->supported_list) { \ const type *p; \ AVIOContext *s = NULL; \ uint8_t *ret; \ int len; \ \ if (avio_open_dyn_buf(&s) < 0) \ - exit_program(1); \ + exit(1); \ \ for (p = ost->enc->supported_list; *p != none; p++) { \ get_name(*p); \ - avio_printf(s, "%s" separator, name); \ + avio_printf(s, "%s|", name); \ } \ len = avio_close_dyn_buf(s, &ret); \ ret[len - 1] = 0; \ @@ -59,48 +60,44 @@ static char *choose_ ## var ## s(OutputStream *ost) \ return NULL; \ } -DEF_CHOOSE_FORMAT(enum PixelFormat, pix_fmt, pix_fmts, PIX_FMT_NONE, - GET_PIX_FMT_NAME, ":") +DEF_CHOOSE_FORMAT(enum AVPixelFormat, pix_fmt, pix_fmts, AV_PIX_FMT_NONE, + GET_PIX_FMT_NAME) DEF_CHOOSE_FORMAT(enum AVSampleFormat, sample_fmt, sample_fmts, - AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME, ",") + AV_SAMPLE_FMT_NONE, GET_SAMPLE_FMT_NAME) DEF_CHOOSE_FORMAT(int, sample_rate, supported_samplerates, 0, - GET_SAMPLE_RATE_NAME, ",") + GET_SAMPLE_RATE_NAME) DEF_CHOOSE_FORMAT(uint64_t, channel_layout, channel_layouts, 0, - GET_CH_LAYOUT_NAME, ",") + GET_CH_LAYOUT_NAME) FilterGraph *init_simple_filtergraph(InputStream *ist, OutputStream *ost) { FilterGraph *fg = av_mallocz(sizeof(*fg)); if (!fg) - exit_program(1); + exit(1); fg->index = nb_filtergraphs; - fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs), &fg->nb_outputs, - fg->nb_outputs + 1); + GROW_ARRAY(fg->outputs, fg->nb_outputs); if (!(fg->outputs[0] = av_mallocz(sizeof(*fg->outputs[0])))) - exit_program(1); + exit(1); fg->outputs[0]->ost = ost; fg->outputs[0]->graph = fg; ost->filter = fg->outputs[0]; - fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs), &fg->nb_inputs, - fg->nb_inputs + 1); + GROW_ARRAY(fg->inputs, fg->nb_inputs); if (!(fg->inputs[0] = av_mallocz(sizeof(*fg->inputs[0])))) - exit_program(1); + exit(1); fg->inputs[0]->ist = ist; fg->inputs[0]->graph = fg; - ist->filters = grow_array(ist->filters, sizeof(*ist->filters), - &ist->nb_filters, ist->nb_filters + 1); + GROW_ARRAY(ist->filters, ist->nb_filters); ist->filters[ist->nb_filters - 1] = fg->inputs[0]; - filtergraphs = grow_array(filtergraphs, sizeof(*filtergraphs), - &nb_filtergraphs, nb_filtergraphs + 1); + GROW_ARRAY(filtergraphs, nb_filtergraphs); filtergraphs[nb_filtergraphs - 1] = fg; return fg; @@ -116,7 +113,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) if (type != AVMEDIA_TYPE_VIDEO && type != AVMEDIA_TYPE_AUDIO) { av_log(NULL, AV_LOG_FATAL, "Only video and audio filters supported " "currently.\n"); - exit_program(1); + exit(1); } if (in->name) { @@ -128,7 +125,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) if (file_idx < 0 || file_idx >= nb_input_files) { av_log(NULL, AV_LOG_FATAL, "Invalid file index %d in filtegraph description %s.\n", file_idx, fg->graph_desc); - exit_program(1); + exit(1); } s = input_files[file_idx]->ctx; @@ -143,7 +140,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) if (!st) { av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s " "matches no streams.\n", p, fg->graph_desc); - exit_program(1); + exit(1); } ist = input_streams[input_files[file_idx]->ist_index + st->index]; } else { @@ -157,7 +154,7 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) av_log(NULL, AV_LOG_FATAL, "Cannot find a matching stream for " "unlabeled input pad %d on filter %s", in->pad_idx, in->filter_ctx->name); - exit_program(1); + exit(1); } } av_assert0(ist); @@ -166,18 +163,68 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) ist->decoding_needed = 1; ist->st->discard = AVDISCARD_NONE; - fg->inputs = grow_array(fg->inputs, sizeof(*fg->inputs), - &fg->nb_inputs, fg->nb_inputs + 1); + GROW_ARRAY(fg->inputs, fg->nb_inputs); if (!(fg->inputs[fg->nb_inputs - 1] = av_mallocz(sizeof(*fg->inputs[0])))) - exit_program(1); + exit(1); fg->inputs[fg->nb_inputs - 1]->ist = ist; fg->inputs[fg->nb_inputs - 1]->graph = fg; - ist->filters = grow_array(ist->filters, sizeof(*ist->filters), - &ist->nb_filters, ist->nb_filters + 1); + GROW_ARRAY(ist->filters, ist->nb_filters); ist->filters[ist->nb_filters - 1] = fg->inputs[fg->nb_inputs - 1]; } +static int insert_trim(OutputStream *ost, AVFilterContext **last_filter, int *pad_idx) +{ + OutputFile *of = output_files[ost->file_index]; + AVFilterGraph *graph = (*last_filter)->graph; + AVFilterContext *ctx; + const AVFilter *trim; + const char *name = ost->st->codec->codec_type == AVMEDIA_TYPE_VIDEO ? "trim" : "atrim"; + char filter_name[128]; + int ret = 0; + + if (of->recording_time == INT64_MAX && !of->start_time) + return 0; + + trim = avfilter_get_by_name(name); + if (!trim) { + av_log(NULL, AV_LOG_ERROR, "%s filter not present, cannot limit " + "recording time.\n", name); + return AVERROR_FILTER_NOT_FOUND; + } + + snprintf(filter_name, sizeof(filter_name), "%s for output stream %d:%d", + name, ost->file_index, ost->index); + ctx = avfilter_graph_alloc_filter(graph, trim, filter_name); + if (!ctx) + return AVERROR(ENOMEM); + + if (of->recording_time != INT64_MAX) { + ret = av_opt_set_double(ctx, "duration", (double)of->recording_time / 1e6, + AV_OPT_SEARCH_CHILDREN); + } + if (ret >= 0 && of->start_time) { + ret = av_opt_set_double(ctx, "start", (double)of->start_time / 1e6, + AV_OPT_SEARCH_CHILDREN); + } + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Error configuring the %s filter", name); + return ret; + } + + ret = avfilter_init_str(ctx, NULL); + if (ret < 0) + return ret; + + ret = avfilter_link(*last_filter, *pad_idx, ctx, 0); + if (ret < 0) + return ret; + + *last_filter = ctx; + *pad_idx = 0; + return 0; +} + static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, AVFilterInOut *out) { char *pix_fmts; @@ -191,7 +238,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, snprintf(name, sizeof(name), "output stream %d:%d", ost->file_index, ost->index); ret = avfilter_graph_create_filter(&ofilter->filter, avfilter_get_by_name("buffersink"), - name, NULL, pix_fmts, fg->graph); + name, NULL, NULL, fg->graph); if (ret < 0) return ret; @@ -252,6 +299,11 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } + ret = insert_trim(ost, &last_filter, &pad_idx); + if (ret < 0) + return ret; + + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; @@ -318,6 +370,10 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } + ret = insert_trim(ost, &last_filter, &pad_idx); + if (ret < 0) + return ret; + if ((ret = avfilter_link(last_filter, pad_idx, ofilter->filter, 0)) < 0) return ret; @@ -332,7 +388,7 @@ static int configure_output_audio_filter(FilterGraph *fg, OutputFilter *ofilter, AVIOContext *pb; \ \ if (avio_open_dyn_buf(&pb) < 0) \ - exit_program(1); \ + exit(1); \ \ avio_printf(pb, "%s", ctx->filter->name); \ if (nb_pads > 1) \ @@ -428,7 +484,6 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, if (audio_sync_method > 0) { AVFilterContext *async; - char args[256]; int len = 0; av_log(NULL, AV_LOG_WARNING, "-async has been deprecated. Used the " @@ -455,6 +510,29 @@ static int configure_input_audio_filter(FilterGraph *fg, InputFilter *ifilter, first_filter = async; pad_idx = 0; } + if (audio_volume != 256) { + AVFilterContext *volume; + + av_log(NULL, AV_LOG_WARNING, "-vol has been deprecated. Use the volume " + "audio filter instead.\n"); + + snprintf(args, sizeof(args), "volume=%f", audio_volume / 256.0); + + snprintf(name, sizeof(name), "graph %d volume for input stream %d:%d", + fg->index, ist->file_index, ist->st->index); + ret = avfilter_graph_create_filter(&volume, + avfilter_get_by_name("volume"), + name, args, NULL, fg->graph); + if (ret < 0) + return ret; + + ret = avfilter_link(volume, 0, first_filter, pad_idx); + if (ret < 0) + return ret; + + first_filter = volume; + pad_idx = 0; + } if ((ret = avfilter_link(ifilter->filter, 0, first_filter, pad_idx)) < 0) return ret; @@ -487,9 +565,20 @@ int configure_filtergraph(FilterGraph *fg) if (simple) { OutputStream *ost = fg->outputs[0]->ost; - char args[255]; + char args[512]; + AVDictionaryEntry *e = NULL; + snprintf(args, sizeof(args), "flags=0x%X", (unsigned)ost->sws_flags); fg->graph->scale_sws_opts = av_strdup(args); + + args[0] = '\0'; + while ((e = av_dict_get(fg->outputs[0]->ost->resample_opts, "", e, + AV_DICT_IGNORE_SUFFIX))) { + av_strlcatf(args, sizeof(args), "%s=%s:", e->key, e->value); + } + if (strlen(args)) + args[strlen(args) - 1] = '\0'; + fg->graph->resample_lavr_opts = av_strdup(args); } if ((ret = avfilter_graph_parse2(fg->graph, graph_desc, &inputs, &outputs)) < 0) @@ -521,10 +610,9 @@ int configure_filtergraph(FilterGraph *fg) } else { /* wait until output mappings are processed */ for (cur = outputs; cur;) { - fg->outputs = grow_array(fg->outputs, sizeof(*fg->outputs), - &fg->nb_outputs, fg->nb_outputs + 1); + GROW_ARRAY(fg->outputs, fg->nb_outputs); if (!(fg->outputs[fg->nb_outputs - 1] = av_mallocz(sizeof(*fg->outputs[0])))) - exit_program(1); + exit(1); fg->outputs[fg->nb_outputs - 1]->graph = fg; fg->outputs[fg->nb_outputs - 1]->out_tmp = cur; cur = cur->next;