* commit '1ae44c87c924b69a0657256fbaa8ad140df2f27c':
lavfi/gradfun: remove rounding to match C and SSE code.
lavfi/gradfun: fix dithering in MMX code.
lavfi/gradfun: fix rounding in MMX code.
lavfi/gradfun: do not increment DC pointer for odd values.
fate: filter: Add dependencies
avconv: add options for reading filtergraphs from a file.
Conflicts:
Changelog
doc/ffmpeg.texi
doc/filters.texi
ffmpeg.h
ffmpeg_opt.c
libavfilter/vf_gradfun.c
tests/fate/filter.mak
Merged-by: Michael Niedermayer <michaelni@gmx.at>
... | ... |
@@ -12,6 +12,8 @@ version <next>: |
12 | 12 |
- 10% faster aac encoding on x86 and MIPS |
13 | 13 |
- sine audio filter source |
14 | 14 |
- WebP demuxing and decoding support |
15 |
+- new ffmpeg options -filter_script and -filter_complex_script, which allow a |
|
16 |
+ filtergraph description to be read from a file |
|
15 | 17 |
|
16 | 18 |
|
17 | 19 |
version 1.2: |
... | ... |
@@ -359,6 +359,11 @@ syntax. |
359 | 359 |
See the @ref{filter_complex_option,,-filter_complex option} if you |
360 | 360 |
want to create filter graphs with multiple inputs and/or outputs. |
361 | 361 |
|
362 |
+@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream}) |
|
363 |
+This option is similar to @option{-filter}, the only difference is that its |
|
364 |
+argument is the name of the file from which a filtergraph description is to be |
|
365 |
+read. |
|
366 |
+ |
|
362 | 367 |
@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream}) |
363 | 368 |
Specify the preset for matching stream(s). |
364 | 369 |
|
... | ... |
@@ -1049,6 +1054,11 @@ ffmpeg -filter_complex 'color=c=red' -t 5 out.mkv |
1049 | 1049 |
Define a complex filter graph, i.e. one with arbitrary number of inputs and/or |
1050 | 1050 |
outputs. Equivalent to @option{-filter_complex}. |
1051 | 1051 |
|
1052 |
+@item -filter_complex_script @var{filename} (@emph{global}) |
|
1053 |
+This option is similar to @option{-filter_complex}, the only difference is that |
|
1054 |
+its argument is the name of the file from which a complex filtergraph |
|
1055 |
+description is to be read. |
|
1056 |
+ |
|
1052 | 1057 |
@end table |
1053 | 1058 |
|
1054 | 1059 |
As a special exception, you can use a bitmap subtitle stream as input: it |
... | ... |
@@ -165,6 +165,8 @@ typedef struct OptionsContext { |
165 | 165 |
int nb_copy_prior_start; |
166 | 166 |
SpecifierOpt *filters; |
167 | 167 |
int nb_filters; |
168 |
+ SpecifierOpt *filter_scripts; |
|
169 |
+ int nb_filter_scripts; |
|
168 | 170 |
SpecifierOpt *reinit_filters; |
169 | 171 |
int nb_reinit_filters; |
170 | 172 |
SpecifierOpt *fix_sub_duration; |
... | ... |
@@ -1103,6 +1103,59 @@ static void parse_matrix_coeffs(uint16_t *dest, const char *str) |
1103 | 1103 |
} |
1104 | 1104 |
} |
1105 | 1105 |
|
1106 |
+/* read file contents into a string */ |
|
1107 |
+static uint8_t *read_file(const char *filename) |
|
1108 |
+{ |
|
1109 |
+ AVIOContext *pb = NULL; |
|
1110 |
+ AVIOContext *dyn_buf = NULL; |
|
1111 |
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ); |
|
1112 |
+ uint8_t buf[1024], *str; |
|
1113 |
+ |
|
1114 |
+ if (ret < 0) { |
|
1115 |
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename); |
|
1116 |
+ return NULL; |
|
1117 |
+ } |
|
1118 |
+ |
|
1119 |
+ ret = avio_open_dyn_buf(&dyn_buf); |
|
1120 |
+ if (ret < 0) { |
|
1121 |
+ avio_closep(&pb); |
|
1122 |
+ return NULL; |
|
1123 |
+ } |
|
1124 |
+ while ((ret = avio_read(pb, buf, sizeof(buf))) > 0) |
|
1125 |
+ avio_write(dyn_buf, buf, ret); |
|
1126 |
+ avio_w8(dyn_buf, 0); |
|
1127 |
+ avio_closep(&pb); |
|
1128 |
+ |
|
1129 |
+ ret = avio_close_dyn_buf(dyn_buf, &str); |
|
1130 |
+ if (ret < 0) |
|
1131 |
+ return NULL; |
|
1132 |
+ return str; |
|
1133 |
+} |
|
1134 |
+ |
|
1135 |
+static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc, |
|
1136 |
+ OutputStream *ost) |
|
1137 |
+{ |
|
1138 |
+ AVStream *st = ost->st; |
|
1139 |
+ char *filter = NULL, *filter_script = NULL; |
|
1140 |
+ |
|
1141 |
+ MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st); |
|
1142 |
+ MATCH_PER_STREAM_OPT(filters, str, filter, oc, st); |
|
1143 |
+ |
|
1144 |
+ if (filter_script && filter) { |
|
1145 |
+ av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for " |
|
1146 |
+ "output stream #%d:%d.\n", nb_output_files, st->index); |
|
1147 |
+ exit(1); |
|
1148 |
+ } |
|
1149 |
+ |
|
1150 |
+ if (filter_script) |
|
1151 |
+ return read_file(filter_script); |
|
1152 |
+ else if (filter) |
|
1153 |
+ return av_strdup(filter); |
|
1154 |
+ |
|
1155 |
+ return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ? |
|
1156 |
+ "null" : "anull"); |
|
1157 |
+} |
|
1158 |
+ |
|
1106 | 1159 |
static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, int source_index) |
1107 | 1160 |
{ |
1108 | 1161 |
AVStream *st; |
... | ... |
@@ -1125,7 +1178,6 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in |
1125 | 1125 |
char *frame_size = NULL; |
1126 | 1126 |
char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL; |
1127 | 1127 |
char *intra_matrix = NULL, *inter_matrix = NULL; |
1128 |
- const char *filters = "null"; |
|
1129 | 1128 |
int do_pass = 0; |
1130 | 1129 |
int i; |
1131 | 1130 |
|
... | ... |
@@ -1236,8 +1288,10 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in |
1236 | 1236 |
ost->top_field_first = -1; |
1237 | 1237 |
MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st); |
1238 | 1238 |
|
1239 |
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); |
|
1240 |
- ost->avfilter = av_strdup(filters); |
|
1239 |
+ |
|
1240 |
+ ost->avfilter = get_ost_filters(o, oc, ost); |
|
1241 |
+ if (!ost->avfilter) |
|
1242 |
+ exit(1); |
|
1241 | 1243 |
} else { |
1242 | 1244 |
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st); |
1243 | 1245 |
} |
... | ... |
@@ -1260,7 +1314,6 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in |
1260 | 1260 |
|
1261 | 1261 |
if (!ost->stream_copy) { |
1262 | 1262 |
char *sample_fmt = NULL; |
1263 |
- const char *filters = "anull"; |
|
1264 | 1263 |
|
1265 | 1264 |
MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st); |
1266 | 1265 |
|
... | ... |
@@ -1273,10 +1326,9 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in |
1273 | 1273 |
|
1274 | 1274 |
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st); |
1275 | 1275 |
|
1276 |
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); |
|
1277 |
- |
|
1278 |
- av_assert1(filters); |
|
1279 |
- ost->avfilter = av_strdup(filters); |
|
1276 |
+ ost->avfilter = get_ost_filters(o, oc, ost); |
|
1277 |
+ if (!ost->avfilter) |
|
1278 |
+ exit(1); |
|
1280 | 1279 |
|
1281 | 1280 |
/* check for channel mapping for this audio stream */ |
1282 | 1281 |
for (n = 0; n < o->nb_audio_channel_maps; n++) { |
... | ... |
@@ -2291,8 +2343,24 @@ static int opt_filter_complex(void *optctx, const char *opt, const char *arg) |
2291 | 2291 |
GROW_ARRAY(filtergraphs, nb_filtergraphs); |
2292 | 2292 |
if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0])))) |
2293 | 2293 |
return AVERROR(ENOMEM); |
2294 |
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
2295 |
- filtergraphs[nb_filtergraphs - 1]->graph_desc = arg; |
|
2294 |
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
2295 |
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg); |
|
2296 |
+ if (!filtergraphs[nb_filtergraphs - 1]->graph_desc) |
|
2297 |
+ return AVERROR(ENOMEM); |
|
2298 |
+ return 0; |
|
2299 |
+} |
|
2300 |
+ |
|
2301 |
+static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg) |
|
2302 |
+{ |
|
2303 |
+ uint8_t *graph_desc = read_file(arg); |
|
2304 |
+ if (!graph_desc) |
|
2305 |
+ return AVERROR(EINVAL); |
|
2306 |
+ |
|
2307 |
+ GROW_ARRAY(filtergraphs, nb_filtergraphs); |
|
2308 |
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0])))) |
|
2309 |
+ return AVERROR(ENOMEM); |
|
2310 |
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
2311 |
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc; |
|
2296 | 2312 |
return 0; |
2297 | 2313 |
} |
2298 | 2314 |
|
... | ... |
@@ -2590,12 +2658,16 @@ const OptionDef options[] = { |
2590 | 2590 |
"set profile", "profile" }, |
2591 | 2591 |
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) }, |
2592 | 2592 |
"set stream filtergraph", "filter_graph" }, |
2593 |
+ { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) }, |
|
2594 |
+ "read stream filtergraph description from a file", "filename" }, |
|
2593 | 2595 |
{ "reinit_filter", HAS_ARG | OPT_INT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(reinit_filters) }, |
2594 | 2596 |
"reinit filtergraph on input parameter changes", "" }, |
2595 | 2597 |
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex }, |
2596 | 2598 |
"create a complex filtergraph", "graph_description" }, |
2597 | 2599 |
{ "lavfi", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex }, |
2598 | 2600 |
"create a complex filtergraph", "graph_description" }, |
2601 |
+ { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script }, |
|
2602 |
+ "read complex filtergraph description from a file", "filename" }, |
|
2599 | 2603 |
{ "stats", OPT_BOOL, { &print_stats }, |
2600 | 2604 |
"print progress report during encoding", }, |
2601 | 2605 |
{ "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT | |
... | ... |
@@ -1,3 +1,7 @@ |
1 |
+FILTERDEMDEC = $(call ALLYES, $(1)_FILTER $(2)_DEMUXER $(3)_DECODER) |
|
2 |
+FILTERDEMDECMUX = $(call ALLYES, $(1)_FILTER $(2)_DEMUXER $(3)_DECODER $(4)_MUXER) |
|
3 |
+FILTERDEMDECENCMUX = $(call ALLYES, $(1)_FILTER $(2)_DEMUXER $(3)_DECODER $(4)_ENCODER $(5)_MUXER) |
|
4 |
+ |
|
1 | 5 |
FATE_AMIX += fate-filter-amix-simple |
2 | 6 |
fate-filter-amix-simple: CMD = ffmpeg -filter_complex amix -i $(SRC) -ss 3 -i $(SRC1) -f f32le - |
3 | 7 |
fate-filter-amix-simple: REF = $(SAMPLES)/filter/amix_simple.pcm |
... | ... |
@@ -18,9 +22,9 @@ $(FATE_AMIX): SRC1 = $(TARGET_PATH)/tests/data/asynth-44100-2-2.wav |
18 | 18 |
$(FATE_AMIX): CMP = oneoff |
19 | 19 |
$(FATE_AMIX): CMP_UNIT = f32 |
20 | 20 |
|
21 |
-FATE_FILTER-$(CONFIG_AMIX_FILTER) += $(FATE_AMIX) |
|
21 |
+FATE_FILTER-$(call FILTERDEMDECENCMUX, AMIX, WAV, PCM_S16LE, PCM_F32LE, PCM_F32LE) += $(FATE_AMIX) |
|
22 | 22 |
|
23 |
-FATE_FILTER-$(CONFIG_ASYNCTS_FILTER) += fate-filter-asyncts |
|
23 |
+FATE_FILTER-$(call FILTERDEMDECMUX, ASYNCTS, FLV, NELLYMOSER, PCM_S16LE) += fate-filter-asyncts |
|
24 | 24 |
fate-filter-asyncts: SRC = $(SAMPLES)/nellymoser/nellymoser-discont.flv |
25 | 25 |
fate-filter-asyncts: CMD = pcm -analyzeduration 10000000 -i $(SRC) -af asyncts |
26 | 26 |
fate-filter-asyncts: CMP = oneoff |
... | ... |
@@ -34,7 +38,7 @@ fate-filter-aresample: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm |
34 | 34 |
|
35 | 35 |
fate-filter-delogo: CMD = framecrc -i $(SAMPLES)/real/rv30.rm -vf perms=random,delogo=show=0:x=290:y=25:w=26:h=16 -an |
36 | 36 |
|
37 |
-FATE_FILTER-$(call ALLYES, PERMS_FILTER DELOGO_FILTER) += fate-filter-delogo |
|
37 |
+FATE_FILTER-$(call ALLYES, PERMS_FILTER DELOGO_FILTER RM_DEMUXER RV30_DECODER) += fate-filter-delogo |
|
38 | 38 |
|
39 | 39 |
FATE_YADIF += fate-filter-yadif-mode0 |
40 | 40 |
fate-filter-yadif-mode0: CMD = framecrc -flags bitexact -idct simple -i $(SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 30 -vf yadif=0 |
... | ... |
@@ -42,7 +46,7 @@ fate-filter-yadif-mode0: CMD = framecrc -flags bitexact -idct simple -i $(SAMPLE |
42 | 42 |
FATE_YADIF += fate-filter-yadif-mode1 |
43 | 43 |
fate-filter-yadif-mode1: CMD = framecrc -flags bitexact -idct simple -i $(SAMPLES)/mpeg2/mpeg2_field_encoding.ts -vframes 59 -vf yadif=1 |
44 | 44 |
|
45 |
-FATE_FILTER-$(CONFIG_YADIF_FILTER) += $(FATE_YADIF) |
|
45 |
+FATE_FILTER-$(call FILTERDEMDEC, YADIF, MPEGTS, MPEG2VIDEO) += $(FATE_YADIF) |
|
46 | 46 |
|
47 | 47 |
FATE_HQDN3D += fate-filter-hqdn3d |
48 | 48 |
fate-filter-hqdn3d: CMD = framecrc -idct simple -i $(SAMPLES)/smjpeg/scenwin.mjpg -vf perms=random,hqdn3d -an |