Originally committed as revision 12734 to svn://svn.ffmpeg.org/ffmpeg/trunk
Unified · Split
| @@ -22,93 +22,39 @@ · 21 unmodified lines | |||
| 22 | #include "avfilter.h" | 22 | #include "avfilter.h" |
| 23 | #include "avfiltergraph.h" | 23 | #include "avfiltergraph.h" |
| 24 | 24 | ||
| 25 | typedef struct AVFilterGraph { | ||
| 26 | unsigned filter_count; | ||
| 27 | AVFilterContext **filters; | ||
| 28 | |||
| 29 | /** fake filters to handle links to internal filters */ | ||
| 30 | AVFilterContext *link_filter_in; | ||
| 31 | AVFilterContext *link_filter_out; | ||
| 32 | } GraphContext; | ||
| 33 | |||
| 34 | typedef struct { | ||
| 35 | AVFilterContext *graph; | ||
| 36 | } GraphLinkContext; | ||
| 37 | |||
| 38 | static int link_init(AVFilterContext *ctx, const char *args, void *opaque) | ||
| 39 | { | ||
| 40 | GraphLinkContext *linkctx = ctx->priv; | ||
| 41 | linkctx->graph = opaque; | ||
| 42 | return !opaque; | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | 25 | /** |
| 46 | * Given the link between the dummy filter and an internal filter whose input | 26 | * For use in av_log |
| 47 | * is being exported outside the graph, this returns the externally visible | ||
| 48 | * link. | ||
| 49 | */ | 27 | */ |
| 50 | static inline AVFilterLink *get_extern_input_link(AVFilterLink *link) | 28 | static const char *log_name(void *p) |
| 51 | { | 29 | { |
| 52 | GraphLinkContext *lctx = link->src->priv; | 30 | return "Filter parser"; |
| 53 | return lctx->graph->inputs[link->srcpad]; | ||
| 54 | } | 31 | } |
| 55 | 32 | ||
| 56 | /** | 33 | static const AVClass filter_parser_class = { |
| 57 | * Given the link between the dummy filter and an internal filter whose output | 34 | "Filter parser", |
| 58 | * is being exported outside the graph, this returns the externally visible | 35 | log_name |
| 59 | * link. | ||
| 60 | */ | ||
| 61 | static inline AVFilterLink *get_extern_output_link(AVFilterLink *link) | ||
| 62 | { | ||
| 63 | GraphLinkContext *lctx = link->dst->priv; | ||
| 64 | return lctx->graph->outputs[link->dstpad]; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | /** dummy filter used to help export filters pads outside the graph */ | ||
| 69 | static AVFilter vf_graph_dummy = | ||
| 70 | { | ||
| 71 | .name = "graph_dummy", | ||
| 72 | |||
| 73 | .priv_size = sizeof(GraphLinkContext), | ||
| 74 | |||
| 75 | .init = link_init, | ||
| 76 | |||
| 77 | .inputs = (AVFilterPad[]) {{ .name = NULL, }}, | ||
| 78 | .outputs = (AVFilterPad[]) {{ .name = NULL, }}, | ||
| 79 | }; | 36 | }; |
| 80 | 37 | ||
| 81 | static void uninit(AVFilterContext *ctx) | 38 | static const AVClass *log_ctx = &filter_parser_class; |
| 82 | { | ||
| 83 | GraphContext *graph = ctx->priv; | ||
| 84 | 39 | ||
| 85 | if(graph->link_filter_in) { | 40 | static void uninit(GraphContext *graph) |
| 86 | avfilter_destroy(graph->link_filter_in); | 41 | { |
| 87 | graph->link_filter_in = NULL; | ||
| 88 | } | ||
| 89 | if(graph->link_filter_out) { | ||
| 90 | avfilter_destroy(graph->link_filter_out); | ||
| 91 | graph->link_filter_out = NULL; | ||
| 92 | } | ||
| 93 | for(; graph->filter_count > 0; graph->filter_count --) | 42 | for(; graph->filter_count > 0; graph->filter_count --) |
| 94 | avfilter_destroy(graph->filters[graph->filter_count - 1]); | 43 | avfilter_destroy(graph->filters[graph->filter_count - 1]); |
| 95 | av_freep(&graph->filters); | 44 | av_freep(&graph->filters); |
| 96 | } | 45 | } |
| 97 | 46 | ||
| 98 | /* TODO: insert in sorted order */ | 47 | /* TODO: insert in sorted order */ |
| 99 | void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter) | 48 | void avfilter_graph_add_filter(GraphContext *graph, AVFilterContext *filter) |
| 100 | { | 49 | { |
| 101 | GraphContext *graph = graphctx->priv; | ||
| 102 | |||
| 103 | graph->filters = av_realloc(graph->filters, | 50 | graph->filters = av_realloc(graph->filters, |
| 104 | sizeof(AVFilterContext*) * ++graph->filter_count); | 51 | sizeof(AVFilterContext*) * ++graph->filter_count); |
| 105 | graph->filters[graph->filter_count - 1] = filter; | 52 | graph->filters[graph->filter_count - 1] = filter; |
| 106 | } | 53 | } |
| 107 | 54 | ||
| 108 | /* search intelligently, once we insert in order */ | 55 | /* search intelligently, once we insert in order */ |
| 109 | AVFilterContext *avfilter_graph_get_filter(AVFilterContext *ctx, char *name) | 56 | AVFilterContext *avfilter_graph_get_filter(GraphContext *graph, char *name) |
| 110 | { | 57 | { |
| 111 | GraphContext *graph = ctx->priv; | ||
| 112 | int i; | 58 | int i; |
| 113 | 59 | ||
| 114 | if(!name) | 60 | if(!name) |
| @@ -121,11 +67,8 @@ AVFilterContext *avfilter_graph_get_filter(AVFilterContext *ctx, char *name) · 6 unmodified lines | |||
| 121 | return NULL; | 67 | return NULL; |
| 122 | } | 68 | } |
| 123 | 69 | ||
| 124 | static int query_formats(AVFilterContext *graphctx) | 70 | static int query_formats(GraphContext *graph) |
| 125 | { | 71 | { |
| 126 | GraphContext *graph = graphctx->priv; | ||
| 127 | AVFilterContext *linkfiltin = graph->link_filter_in; | ||
| 128 | AVFilterContext *linkfiltout = graph->link_filter_out; | ||
| 129 | int i, j; | 72 | int i, j; |
| 130 | 73 | ||
| 131 | /* ask all the sub-filters for their supported colorspaces */ | 74 | /* ask all the sub-filters for their supported colorspaces */ |
| @@ -136,24 +79,6 @@ static int query_formats(AVFilterContext *graphctx) · 4 unmodified lines | |||
| 136 | avfilter_default_query_formats(graph->filters[i]); | 79 | avfilter_default_query_formats(graph->filters[i]); |
| 137 | } | 80 | } |
| 138 | 81 | ||
| 139 | /* use these formats on our exported links */ | ||
| 140 | for(i = 0; i < linkfiltout->input_count; i ++) { | ||
| 141 | avfilter_formats_ref( linkfiltout->inputs[i]->in_formats, | ||
| 142 | &linkfiltout->inputs[i]->out_formats); | ||
| 143 | |||
| 144 | if(graphctx->outputs[i]) | ||
| 145 | avfilter_formats_ref(linkfiltout->inputs[i]->in_formats, | ||
| 146 | &graphctx->outputs[i]->in_formats); | ||
| 147 | } | ||
| 148 | for(i = 0; i < linkfiltin->output_count; i ++) { | ||
| 149 | avfilter_formats_ref( linkfiltin->outputs[i]->out_formats, | ||
| 150 | &linkfiltin->outputs[i]->in_formats); | ||
| 151 | |||
| 152 | if(graphctx->inputs[i]) | ||
| 153 | avfilter_formats_ref(linkfiltin->outputs[i]->out_formats, | ||
| 154 | &graphctx-> inputs[i]->out_formats); | ||
| 155 | } | ||
| 156 | |||
| 157 | /* go through and merge as many format lists as possible */ | 82 | /* go through and merge as many format lists as possible */ |
| 158 | for(i = 0; i < graph->filter_count; i ++) { | 83 | for(i = 0; i < graph->filter_count; i ++) { |
| 159 | AVFilterContext *filter = graph->filters[i]; | 84 | AVFilterContext *filter = graph->filters[i]; |
| @@ -177,7 +102,7 @@ static int query_formats(AVFilterContext *graphctx) · 17 unmodified lines | |||
| 177 | return -1; | 102 | return -1; |
| 178 | } | 103 | } |
| 179 | 104 | ||
| 180 | avfilter_graph_add_filter(graphctx, scale); | 105 | avfilter_graph_add_filter(graph, scale); |
| 181 | scale->filter->query_formats(scale); | 106 | scale->filter->query_formats(scale); |
| 182 | if(!avfilter_merge_formats(scale-> inputs[0]->in_formats, | 107 | if(!avfilter_merge_formats(scale-> inputs[0]->in_formats, |
| 183 | scale-> inputs[0]->out_formats) || | 108 | scale-> inputs[0]->out_formats) || |
| @@ -211,9 +136,6 @@ static void pick_formats(GraphContext *graph) · 27 unmodified lines | |||
| 211 | for(i = 0; i < graph->filter_count; i ++) { | 136 | for(i = 0; i < graph->filter_count; i ++) { |
| 212 | AVFilterContext *filter = graph->filters[i]; | 137 | AVFilterContext *filter = graph->filters[i]; |
| 213 | 138 | ||
| 214 | if(filter->filter == &avfilter_vf_graph) | ||
| 215 | pick_formats(filter->priv); | ||
| 216 | |||
| 217 | for(j = 0; j < filter->input_count; j ++) | 139 | for(j = 0; j < filter->input_count; j ++) |
| 218 | pick_format(filter->inputs[j]); | 140 | pick_format(filter->inputs[j]); |
| 219 | for(j = 0; j < filter->output_count; j ++) | 141 | for(j = 0; j < filter->output_count; j ++) |
| @@ -221,12 +143,10 @@ static void pick_formats(GraphContext *graph) · 1 unmodified line | |||
| 221 | } | 143 | } |
| 222 | } | 144 | } |
| 223 | 145 | ||
| 224 | int avfilter_graph_config_formats(AVFilterContext *graphctx) | 146 | int avfilter_graph_config_formats(GraphContext *graph) |
| 225 | { | 147 | { |
| 226 | GraphContext *graph = graphctx->priv; | ||
| 227 | |||
| 228 | /* find supported formats from sub-filters, and merge along links */ | 148 | /* find supported formats from sub-filters, and merge along links */ |
| 229 | if(query_formats(graphctx)) | 149 | if(query_formats(graph)) |
| 230 | return -1; | 150 | return -1; |
| 231 | 151 | ||
| 232 | /* Once everything is merged, it's possible that we'll still have | 152 | /* Once everything is merged, it's possible that we'll still have |
| @@ -236,7 +156,7 @@ int avfilter_graph_config_formats(AVFilterContext *graphctx) · 3 unmodified lines | |||
| 236 | return 0; | 156 | return 0; |
| 237 | } | 157 | } |
| 238 | 158 | ||
| 239 | static int graph_load_from_desc2(AVFilterContext *ctx, AVFilterGraphDesc *desc) | 159 | static int graph_load_from_desc2(GraphContext *ctx, AVFilterGraphDesc *desc) |
| 240 | { | 160 | { |
| 241 | AVFilterGraphDescFilter *curfilt; | 161 | AVFilterGraphDescFilter *curfilt; |
| 242 | AVFilterGraphDescLink *curlink; | 162 | AVFilterGraphDescLink *curlink; |
| @@ -250,13 +170,13 @@ static int graph_load_from_desc2(AVFilterContext *ctx, AVFilterGraphDesc *desc) · 7 unmodified lines | |||
| 250 | snprintf(tmp, 20, "%d", curfilt->index); | 170 | snprintf(tmp, 20, "%d", curfilt->index); |
| 251 | if(!(filterdef = avfilter_get_by_name(curfilt->filter)) || | 171 | if(!(filterdef = avfilter_get_by_name(curfilt->filter)) || |
| 252 | !(filt = avfilter_open(filterdef, tmp))) { | 172 | !(filt = avfilter_open(filterdef, tmp))) { |
| 253 | av_log(ctx, AV_LOG_ERROR, | 173 | av_log(&log_ctx, AV_LOG_ERROR, |
| 254 | "error creating filter '%s'\n", curfilt->filter); | 174 | "error creating filter '%s'\n", curfilt->filter); |
| 255 | goto fail; | 175 | goto fail; |
| 256 | } | 176 | } |
| 257 | avfilter_graph_add_filter(ctx, filt); | 177 | avfilter_graph_add_filter(ctx, filt); |
| 258 | if(avfilter_init_filter(filt, curfilt->args, NULL)) { | 178 | if(avfilter_init_filter(filt, curfilt->args, NULL)) { |
| 259 | av_log(ctx, AV_LOG_ERROR, | 179 | av_log(&log_ctx, AV_LOG_ERROR, |
| 260 | "error initializing filter '%s'\n", curfilt->filter); | 180 | "error initializing filter '%s'\n", curfilt->filter); |
| 261 | goto fail; | 181 | goto fail; |
| 262 | } | 182 | } |
| @@ -266,16 +186,16 @@ static int graph_load_from_desc2(AVFilterContext *ctx, AVFilterGraphDesc *desc) · 3 unmodified lines | |||
| 266 | for(curlink = desc->links; curlink; curlink = curlink->next) { | 186 | for(curlink = desc->links; curlink; curlink = curlink->next) { |
| 267 | snprintf(tmp, 20, "%d", curlink->src); | 187 | snprintf(tmp, 20, "%d", curlink->src); |
| 268 | if(!(filt = avfilter_graph_get_filter(ctx, tmp))) { | 188 | if(!(filt = avfilter_graph_get_filter(ctx, tmp))) { |
| 269 | av_log(ctx, AV_LOG_ERROR, "link source does not exist in graph\n"); | 189 | av_log(&log_ctx, AV_LOG_ERROR, "link source does not exist in graph\n"); |
| 270 | goto fail; | 190 | goto fail; |
| 271 | } | 191 | } |
| 272 | snprintf(tmp, 20, "%d", curlink->dst); | 192 | snprintf(tmp, 20, "%d", curlink->dst); |
| 273 | if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) { | 193 | if(!(filtb = avfilter_graph_get_filter(ctx, tmp))) { |
| 274 | av_log(ctx, AV_LOG_ERROR, "link destination does not exist in graph\n"); | 194 | av_log(&log_ctx, AV_LOG_ERROR, "link destination does not exist in graph\n"); |
| 275 | goto fail; | 195 | goto fail; |
| 276 | } | 196 | } |
| 277 | if(avfilter_link(filt, curlink->srcpad, filtb, curlink->dstpad)) { | 197 | if(avfilter_link(filt, curlink->srcpad, filtb, curlink->dstpad)) { |
| 278 | av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | 198 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); |
| 279 | goto fail; | 199 | goto fail; |
| 280 | } | 200 | } |
| 281 | } | 201 | } |
| @@ -287,24 +207,24 @@ fail: · 5 unmodified lines | |||
| 287 | return -1; | 207 | return -1; |
| 288 | } | 208 | } |
| 289 | 209 | ||
| 290 | int graph_load_from_desc3(AVFilterContext *ctx, AVFilterGraphDesc *desc, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) | 210 | int graph_load_from_desc3(GraphContext *graph, AVFilterGraphDesc *desc, AVFilterContext *in, int inpad, AVFilterContext *out, int outpad) |
| 291 | { | 211 | { |
| 292 | AVFilterGraphDescExport *curpad; | 212 | AVFilterGraphDescExport *curpad; |
| 293 | char tmp[20]; | 213 | char tmp[20]; |
| 294 | AVFilterContext *filt; | 214 | AVFilterContext *filt; |
| 295 | 215 | ||
| 296 | if (graph_load_from_desc2(ctx, desc) < 0) | 216 | if (graph_load_from_desc2(graph, desc) < 0) |
| 297 | goto fail; | 217 | goto fail; |
| 298 | 218 | ||
| 299 | /* export all input pads */ | 219 | /* export all input pads */ |
| 300 | for(curpad = desc->inputs; curpad; curpad = curpad->next) { | 220 | for(curpad = desc->inputs; curpad; curpad = curpad->next) { |
| 301 | snprintf(tmp, 20, "%d", curpad->filter); | 221 | snprintf(tmp, 20, "%d", curpad->filter); |
| 302 | if(!(filt = avfilter_graph_get_filter(ctx, tmp))) { | 222 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { |
| 303 | av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | 223 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); |
| 304 | goto fail; | 224 | goto fail; |
| 305 | } | 225 | } |
| 306 | if(avfilter_link(in, inpad, filt, curpad->pad)) { | 226 | if(avfilter_link(in, inpad, filt, curpad->pad)) { |
| 307 | av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | 227 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); |
| 308 | goto fail; | 228 | goto fail; |
| 309 | } | 229 | } |
| 310 | } | 230 | } |
| @@ -312,13 +232,13 @@ int graph_load_from_desc3(AVFilterContext *ctx, AVFilterGraphDesc *desc, AVFilte · 1 unmodified line | |||
| 312 | /* export all output pads */ | 232 | /* export all output pads */ |
| 313 | for(curpad = desc->outputs; curpad; curpad = curpad->next) { | 233 | for(curpad = desc->outputs; curpad; curpad = curpad->next) { |
| 314 | snprintf(tmp, 20, "%d", curpad->filter); | 234 | snprintf(tmp, 20, "%d", curpad->filter); |
| 315 | if(!(filt = avfilter_graph_get_filter(ctx, tmp))) { | 235 | if(!(filt = avfilter_graph_get_filter(graph, tmp))) { |
| 316 | av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); | 236 | av_log(&log_ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n"); |
| 317 | goto fail; | 237 | goto fail; |
| 318 | } | 238 | } |
| 319 | 239 | ||
| 320 | if(avfilter_link(filt, curpad->pad, out, outpad)) { | 240 | if(avfilter_link(filt, curpad->pad, out, outpad)) { |
| 321 | av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); | 241 | av_log(&log_ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n"); |
| 322 | goto fail; | 242 | goto fail; |
| 323 | } | 243 | } |
| 324 | } | 244 | } |
| @@ -326,44 +246,6 @@ int graph_load_from_desc3(AVFilterContext *ctx, AVFilterGraphDesc *desc, AVFilte · 1 unmodified line | |||
| 326 | return 0; | 246 | return 0; |
| 327 | 247 | ||
| 328 | fail: | 248 | fail: |
| 329 | uninit(ctx); | 249 | uninit(graph); |
| 330 | return -1; | ||
| 331 | } | ||
| 332 | |||
| 333 | static int init(AVFilterContext *ctx, const char *args, void *opaque) | ||
| 334 | { | ||
| 335 | GraphContext *gctx = ctx->priv; | ||
| 336 | |||
| 337 | if(!(gctx->link_filter_in = avfilter_open(&vf_graph_dummy, NULL))) | ||
| 338 | return -1; | ||
| 339 | if(avfilter_init_filter(gctx->link_filter_in, NULL, ctx)) | ||
| 340 | goto fail; | ||
| 341 | if(!(gctx->link_filter_out = avfilter_open(&vf_graph_dummy, NULL))) | ||
| 342 | goto fail; | ||
| 343 | if(avfilter_init_filter(gctx->link_filter_out, NULL, ctx)) | ||
| 344 | goto fail; | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | |||
| 348 | fail: | ||
| 349 | avfilter_destroy(gctx->link_filter_in); | ||
| 350 | if(gctx->link_filter_out) | ||
| 351 | avfilter_destroy(gctx->link_filter_out); | ||
| 352 | return -1; | 250 | return -1; |
| 353 | } | 251 | } |
| 354 | |||
| 355 | AVFilter avfilter_vf_graph = | ||
| 356 | { | ||
| 357 | .name = "graph", | ||
| 358 | |||
| 359 | .priv_size = sizeof(GraphContext), | ||
| 360 | |||
| 361 | .init = init, | ||
| 362 | .uninit = uninit, | ||
| 363 | |||
| 364 | .query_formats = query_formats, | ||
| 365 | |||
| 366 | .inputs = (AVFilterPad[]) {{ .name = NULL, }}, | ||
| 367 | .outputs = (AVFilterPad[]) {{ .name = NULL, }}, | ||
| 368 | }; | ||
| 369 | |||
| @@ -66,7 +66,10 @@ typedef struct · 65 unmodified lines | |||
| 66 | AVFilterGraphDescExport *outputs; ///< outputs to export | 66 | AVFilterGraphDescExport *outputs; ///< outputs to export |
| 67 | } AVFilterGraphDesc; | 67 | } AVFilterGraphDesc; |
| 68 | 68 | ||
| 69 | extern AVFilter avfilter_vf_graph; | 69 | typedef struct AVFilterGraph { |
| 70 | unsigned filter_count; | ||
| 71 | AVFilterContext **filters; | ||
| 72 | } GraphContext; | ||
| 70 | 73 | ||
| 71 | /** | 74 | /** |
| 72 | * Parse a graph composed of a simple chain of filters which is described by | 75 | * Parse a graph composed of a simple chain of filters which is described by |
| @@ -87,20 +90,20 @@ void avfilter_graph_free_desc(AVFilterGraphDesc *desc); · 14 unmodified lines | |||
| 87 | * @param graph The filter graph | 90 | * @param graph The filter graph |
| 88 | * @param filter The filter to be added | 91 | * @param filter The filter to be added |
| 89 | */ | 92 | */ |
| 90 | void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter); | 93 | void avfilter_graph_add_filter(GraphContext *graphctx, AVFilterContext *filter); |
| 91 | 94 | ||
| 92 | /** | 95 | /** |
| 93 | * Configure the formats of all the links in the graph. | 96 | * Configure the formats of all the links in the graph. |
| 94 | */ | 97 | */ |
| 95 | int avfilter_graph_config_formats(AVFilterContext *graphctx); | 98 | int avfilter_graph_config_formats(GraphContext *graphctx); |
| 96 | 99 | ||
| 97 | /** | 100 | /** |
| 98 | * Configure the parameters (resolution, etc) of all links in the graph. | 101 | * Configure the parameters (resolution, etc) of all links in the graph. |
| 99 | */ | 102 | */ |
| 100 | int avfilter_graph_config_links(AVFilterContext *graphctx); | 103 | int avfilter_graph_config_links(GraphContext *graphctx); |
| 101 | 104 | ||
| 102 | 105 | ||
| 103 | int graph_load_from_desc3(AVFilterContext *ctx, AVFilterGraphDesc *desc, | 106 | int graph_load_from_desc3(GraphContext *ctx, AVFilterGraphDesc *desc, |
| 104 | AVFilterContext *in, int inpad, | 107 | AVFilterContext *in, int inpad, |
| 105 | AVFilterContext *out, int outpad); | 108 | AVFilterContext *out, int outpad); |
| 106 | 109 | ||