... | ... |
@@ -7,6 +7,8 @@ version 10: |
7 | 7 |
- reference-counting for AVFrame and AVPacket data |
8 | 8 |
- avconv now fails when input options are used for output file |
9 | 9 |
or vice versa |
10 |
+- new avconv options -filter_script and -filter_complex_script, which allow a |
|
11 |
+ filtergraph description to be read from a file |
|
10 | 12 |
|
11 | 13 |
|
12 | 14 |
version 9: |
... | ... |
@@ -158,6 +158,8 @@ typedef struct OptionsContext { |
158 | 158 |
int nb_copy_initial_nonkeyframes; |
159 | 159 |
SpecifierOpt *filters; |
160 | 160 |
int nb_filters; |
161 |
+ SpecifierOpt *filter_scripts; |
|
162 |
+ int nb_filter_scripts; |
|
161 | 163 |
SpecifierOpt *pass; |
162 | 164 |
int nb_pass; |
163 | 165 |
SpecifierOpt *passlogfiles; |
... | ... |
@@ -926,6 +926,59 @@ static void parse_matrix_coeffs(uint16_t *dest, const char *str) |
926 | 926 |
} |
927 | 927 |
} |
928 | 928 |
|
929 |
+/* read file contents into a string */ |
|
930 |
+static uint8_t *read_file(const char *filename) |
|
931 |
+{ |
|
932 |
+ AVIOContext *pb = NULL; |
|
933 |
+ AVIOContext *dyn_buf = NULL; |
|
934 |
+ int ret = avio_open(&pb, filename, AVIO_FLAG_READ); |
|
935 |
+ uint8_t buf[1024], *str; |
|
936 |
+ |
|
937 |
+ if (ret < 0) { |
|
938 |
+ av_log(NULL, AV_LOG_ERROR, "Error opening file %s.\n", filename); |
|
939 |
+ return NULL; |
|
940 |
+ } |
|
941 |
+ |
|
942 |
+ ret = avio_open_dyn_buf(&dyn_buf); |
|
943 |
+ if (ret < 0) { |
|
944 |
+ avio_closep(&pb); |
|
945 |
+ return NULL; |
|
946 |
+ } |
|
947 |
+ while ((ret = avio_read(pb, buf, sizeof(buf))) > 0) |
|
948 |
+ avio_write(dyn_buf, buf, ret); |
|
949 |
+ avio_w8(dyn_buf, 0); |
|
950 |
+ avio_closep(&pb); |
|
951 |
+ |
|
952 |
+ ret = avio_close_dyn_buf(dyn_buf, &str); |
|
953 |
+ if (ret < 0) |
|
954 |
+ return NULL; |
|
955 |
+ return str; |
|
956 |
+} |
|
957 |
+ |
|
958 |
+static char *get_ost_filters(OptionsContext *o, AVFormatContext *oc, |
|
959 |
+ OutputStream *ost) |
|
960 |
+{ |
|
961 |
+ AVStream *st = ost->st; |
|
962 |
+ char *filter = NULL, *filter_script = NULL; |
|
963 |
+ |
|
964 |
+ MATCH_PER_STREAM_OPT(filter_scripts, str, filter_script, oc, st); |
|
965 |
+ MATCH_PER_STREAM_OPT(filters, str, filter, oc, st); |
|
966 |
+ |
|
967 |
+ if (filter_script && filter) { |
|
968 |
+ av_log(NULL, AV_LOG_ERROR, "Both -filter and -filter_script set for " |
|
969 |
+ "output stream #%d:%d.\n", nb_output_files, st->index); |
|
970 |
+ exit(1); |
|
971 |
+ } |
|
972 |
+ |
|
973 |
+ if (filter_script) |
|
974 |
+ return read_file(filter_script); |
|
975 |
+ else if (filter) |
|
976 |
+ return av_strdup(filter); |
|
977 |
+ |
|
978 |
+ return av_strdup(st->codec->codec_type == AVMEDIA_TYPE_VIDEO ? |
|
979 |
+ "null" : "anull"); |
|
980 |
+} |
|
981 |
+ |
|
929 | 982 |
static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) |
930 | 983 |
{ |
931 | 984 |
AVStream *st; |
... | ... |
@@ -941,7 +994,6 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) |
941 | 941 |
char *frame_rate = NULL, *frame_size = NULL; |
942 | 942 |
char *frame_aspect_ratio = NULL, *frame_pix_fmt = NULL; |
943 | 943 |
char *intra_matrix = NULL, *inter_matrix = NULL; |
944 |
- const char *filters = "null"; |
|
945 | 944 |
int do_pass = 0; |
946 | 945 |
int i; |
947 | 946 |
|
... | ... |
@@ -1036,8 +1088,10 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc) |
1036 | 1036 |
ost->top_field_first = -1; |
1037 | 1037 |
MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st); |
1038 | 1038 |
|
1039 |
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); |
|
1040 |
- ost->avfilter = av_strdup(filters); |
|
1039 |
+ |
|
1040 |
+ ost->avfilter = get_ost_filters(o, oc, ost); |
|
1041 |
+ if (!ost->avfilter) |
|
1042 |
+ exit(1); |
|
1041 | 1043 |
} else { |
1042 | 1044 |
MATCH_PER_STREAM_OPT(copy_initial_nonkeyframes, i, ost->copy_initial_nonkeyframes, oc ,st); |
1043 | 1045 |
} |
... | ... |
@@ -1059,7 +1113,6 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) |
1059 | 1059 |
|
1060 | 1060 |
if (!ost->stream_copy) { |
1061 | 1061 |
char *sample_fmt = NULL; |
1062 |
- const char *filters = "anull"; |
|
1063 | 1062 |
|
1064 | 1063 |
MATCH_PER_STREAM_OPT(audio_channels, i, audio_enc->channels, oc, st); |
1065 | 1064 |
|
... | ... |
@@ -1072,8 +1125,9 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc) |
1072 | 1072 |
|
1073 | 1073 |
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st); |
1074 | 1074 |
|
1075 |
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, st); |
|
1076 |
- ost->avfilter = av_strdup(filters); |
|
1075 |
+ ost->avfilter = get_ost_filters(o, oc, ost); |
|
1076 |
+ if (!ost->avfilter) |
|
1077 |
+ exit(1); |
|
1077 | 1078 |
} |
1078 | 1079 |
|
1079 | 1080 |
return ost; |
... | ... |
@@ -1878,8 +1932,24 @@ static int opt_filter_complex(void *optctx, const char *opt, const char *arg) |
1878 | 1878 |
GROW_ARRAY(filtergraphs, nb_filtergraphs); |
1879 | 1879 |
if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0])))) |
1880 | 1880 |
return AVERROR(ENOMEM); |
1881 |
- filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
1882 |
- filtergraphs[nb_filtergraphs - 1]->graph_desc = arg; |
|
1881 |
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
1882 |
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg); |
|
1883 |
+ if (!filtergraphs[nb_filtergraphs - 1]->graph_desc) |
|
1884 |
+ return AVERROR(ENOMEM); |
|
1885 |
+ return 0; |
|
1886 |
+} |
|
1887 |
+ |
|
1888 |
+static int opt_filter_complex_script(void *optctx, const char *opt, const char *arg) |
|
1889 |
+{ |
|
1890 |
+ uint8_t *graph_desc = read_file(arg); |
|
1891 |
+ if (!graph_desc) |
|
1892 |
+ return AVERROR(EINVAL); |
|
1893 |
+ |
|
1894 |
+ GROW_ARRAY(filtergraphs, nb_filtergraphs); |
|
1895 |
+ if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0])))) |
|
1896 |
+ return AVERROR(ENOMEM); |
|
1897 |
+ filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1; |
|
1898 |
+ filtergraphs[nb_filtergraphs - 1]->graph_desc = graph_desc; |
|
1883 | 1899 |
return 0; |
1884 | 1900 |
} |
1885 | 1901 |
|
... | ... |
@@ -2138,8 +2208,12 @@ const OptionDef options[] = { |
2138 | 2138 |
"use fixed quality scale (VBR)", "q" }, |
2139 | 2139 |
{ "filter", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filters) }, |
2140 | 2140 |
"set stream filterchain", "filter_list" }, |
2141 |
+ { "filter_script", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(filter_scripts) }, |
|
2142 |
+ "read stream filtergraph description from a file", "filename" }, |
|
2141 | 2143 |
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex }, |
2142 | 2144 |
"create a complex filtergraph", "graph_description" }, |
2145 |
+ { "filter_complex_script", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex_script }, |
|
2146 |
+ "read complex filtergraph description from a file", "filename" }, |
|
2143 | 2147 |
{ "stats", OPT_BOOL, { &print_stats }, |
2144 | 2148 |
"print progress report during encoding", }, |
2145 | 2149 |
{ "attach", HAS_ARG | OPT_PERFILE | OPT_EXPERT | |
... | ... |
@@ -330,6 +330,12 @@ the stream. Use @code{-filters} to show all the available filters |
330 | 330 |
|
331 | 331 |
See also the @option{-filter_complex} option if you want to create filter graphs |
332 | 332 |
with multiple inputs and/or outputs. |
333 |
+ |
|
334 |
+@item -filter_script[:@var{stream_specifier}] @var{filename} (@emph{output,per-stream}) |
|
335 |
+This option is similar to @option{-filter}, the only difference is that its |
|
336 |
+argument is the name of the file from which a filtergraph description is to be |
|
337 |
+read. |
|
338 |
+ |
|
333 | 339 |
@item -pre[:@var{stream_specifier}] @var{preset_name} (@emph{output,per-stream}) |
334 | 340 |
Specify the preset for matching stream(s). |
335 | 341 |
|
... | ... |
@@ -823,6 +829,12 @@ To generate 5 seconds of pure red video using lavfi @code{color} source: |
823 | 823 |
@example |
824 | 824 |
avconv -filter_complex 'color=red' -t 5 out.mkv |
825 | 825 |
@end example |
826 |
+ |
|
827 |
+@item -filter_complex_script @var{filename} (@emph{global}) |
|
828 |
+This option is similar to @option{-filter_complex}, the only difference is that |
|
829 |
+its argument is the name of the file from which a complex filtergraph |
|
830 |
+description is to be read. |
|
831 |
+ |
|
826 | 832 |
@end table |
827 | 833 |
@c man end OPTIONS |
828 | 834 |
|