You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

681 lines
19KB

  1. /*
  2. * filter graphs
  3. * copyright (c) 2007 Bobby Bingham
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avfilter.h"
  22. #include "avfiltergraph.h"
  23. #include "allfilters.h"
  24. typedef struct AVFilterGraph {
  25. unsigned filter_count;
  26. AVFilterContext **filters;
  27. /** fake filters to handle links to internal filters */
  28. AVFilterContext *link_filter_in;
  29. AVFilterContext *link_filter_out;
  30. } GraphContext;
  31. typedef struct {
  32. AVFilterContext *graph;
  33. } GraphLinkContext;
  34. static int link_init(AVFilterContext *ctx, const char *args, void *opaque)
  35. {
  36. GraphLinkContext *linkctx = ctx->priv;
  37. linkctx->graph = opaque;
  38. return !opaque;
  39. }
  40. /**
  41. * Given the link between the dummy filter and an internal filter whose input
  42. * is being exported outside the graph, this returns the externally visible
  43. * link.
  44. */
  45. static inline AVFilterLink *get_extern_input_link(AVFilterLink *link)
  46. {
  47. GraphLinkContext *lctx = link->src->priv;
  48. return lctx->graph->inputs[link->srcpad];
  49. }
  50. /** request a frame from a filter providing input to the graph */
  51. static int link_in_request_frame(AVFilterLink *link)
  52. {
  53. AVFilterLink *link2 = get_extern_input_link(link);
  54. if(!link2)
  55. return -1;
  56. return avfilter_request_frame(link2);
  57. }
  58. static int link_in_poll_frame(AVFilterLink *link)
  59. {
  60. AVFilterLink *link2 = get_extern_input_link(link);
  61. if(!link2)
  62. return -1;
  63. return avfilter_poll_frame(link2);
  64. }
  65. static int link_in_config_props(AVFilterLink *link)
  66. {
  67. AVFilterLink *link2 = get_extern_input_link(link);
  68. int (*config_props)(AVFilterLink *);
  69. int ret;
  70. if(!link2)
  71. return -1;
  72. if(!(config_props = link2->src->output_pads[link2->srcpad].config_props))
  73. config_props = avfilter_default_config_output_link;
  74. ret = config_props(link2);
  75. link->w = link2->w;
  76. link->h = link2->h;
  77. return ret;
  78. }
  79. /**
  80. * Given the link between the dummy filter and an internal filter whose input
  81. * is being exported outside the graph, this returns the externally visible
  82. * link.
  83. */
  84. static inline AVFilterLink *get_extern_output_link(AVFilterLink *link)
  85. {
  86. GraphLinkContext *lctx = link->dst->priv;
  87. return lctx->graph->outputs[link->dstpad];
  88. }
  89. static int link_out_config_props(AVFilterLink *link)
  90. {
  91. AVFilterLink *link2 = get_extern_output_link(link);
  92. if(!link2)
  93. return 0;
  94. link2->w = link->w;
  95. link2->h = link->h;
  96. return 0;
  97. }
  98. static void link_out_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
  99. {
  100. AVFilterLink *link2 = get_extern_output_link(link);
  101. if(!link2)
  102. avfilter_unref_pic(picref);
  103. else
  104. avfilter_start_frame(link2, picref);
  105. }
  106. static void link_out_end_frame(AVFilterLink *link)
  107. {
  108. AVFilterLink *link2 = get_extern_output_link(link);
  109. if(link2)
  110. avfilter_end_frame(link2);
  111. }
  112. static AVFilterPicRef *link_out_get_video_buffer(AVFilterLink *link, int perms)
  113. {
  114. AVFilterLink *link2 = get_extern_output_link(link);
  115. if(!link2)
  116. return NULL;
  117. else
  118. return avfilter_get_video_buffer(link2, perms);
  119. }
  120. static void link_out_draw_slice(AVFilterLink *link, int y, int height)
  121. {
  122. AVFilterLink *link2 = get_extern_output_link(link);
  123. if(link2)
  124. avfilter_draw_slice(link2, y, height);
  125. }
  126. /** dummy filter used to help export filters pads outside the graph */
  127. static AVFilter vf_graph_dummy =
  128. {
  129. .name = "graph_dummy",
  130. .author = "Bobby Bingham",
  131. .priv_size = sizeof(GraphLinkContext),
  132. .init = link_init,
  133. .inputs = (AVFilterPad[]) {{ .name = NULL, }},
  134. .outputs = (AVFilterPad[]) {{ .name = NULL, }},
  135. };
  136. static AVFilterLink *get_intern_input_link(AVFilterLink *link)
  137. {
  138. GraphContext *graph = link->dst->priv;
  139. return graph->link_filter_in->outputs[link->dstpad];
  140. }
  141. static void graph_in_start_frame(AVFilterLink *link, AVFilterPicRef *picref)
  142. {
  143. AVFilterLink *link2 = get_intern_input_link(link);
  144. if(link2)
  145. avfilter_start_frame(link2, picref);
  146. }
  147. static void graph_in_end_frame(AVFilterLink *link)
  148. {
  149. AVFilterLink *link2 = get_intern_input_link(link);
  150. if(link2)
  151. avfilter_end_frame(link2);
  152. }
  153. static AVFilterPicRef *graph_in_get_video_buffer(AVFilterLink *link, int perms)
  154. {
  155. AVFilterLink *link2 = get_intern_input_link(link);
  156. if(link2)
  157. return avfilter_get_video_buffer(link2, perms);
  158. return NULL;
  159. }
  160. static void graph_in_draw_slice(AVFilterLink *link, int y, int height)
  161. {
  162. AVFilterLink *link2 = get_intern_input_link(link);
  163. if(link2)
  164. avfilter_draw_slice(link2, y, height);
  165. }
  166. static int graph_in_config_props(AVFilterLink *link)
  167. {
  168. AVFilterLink *link2 = get_intern_input_link(link);
  169. int (*config_props)(AVFilterLink *);
  170. int ret;
  171. if(!link2)
  172. return -1;
  173. /* copy link properties over to the dummy internal link */
  174. link2->w = link->w;
  175. link2->h = link->h;
  176. link2->format = link->format;
  177. if(!(config_props = link2->dst->input_pads[link2->dstpad].config_props))
  178. return 0; /* FIXME? */
  179. //config_props = avfilter_default_config_input_link;
  180. if(!(ret = config_props(link2)))
  181. link2->init_state = AVLINK_INIT;
  182. else
  183. link2->init_state = AVLINK_STARTINIT;
  184. return ret;
  185. }
  186. static AVFilterLink *get_intern_output_link(AVFilterLink *link)
  187. {
  188. GraphContext *graph = link->src->priv;
  189. return graph->link_filter_out->inputs[link->srcpad];
  190. }
  191. static int graph_out_request_frame(AVFilterLink *link)
  192. {
  193. AVFilterLink *link2 = get_intern_output_link(link);
  194. if(link2)
  195. return avfilter_request_frame(link2);
  196. return -1;
  197. }
  198. static int graph_out_poll_frame(AVFilterLink *link)
  199. {
  200. AVFilterLink *link2 = get_intern_output_link(link);
  201. if(!link2)
  202. return -1;
  203. return avfilter_poll_frame(link2);
  204. }
  205. static int graph_out_config_props(AVFilterLink *link)
  206. {
  207. GraphContext *graph = link->src->priv;
  208. AVFilterLink *link2 = graph->link_filter_out->inputs[link->srcpad];
  209. int ret;
  210. if((ret = avfilter_config_links(graph->link_filter_out)))
  211. return ret;
  212. if(!link2)
  213. return 0;
  214. link->w = link2->w;
  215. link->h = link2->h;
  216. link->format = link2->format;
  217. return 0;
  218. }
  219. static int add_graph_input(AVFilterContext *gctx, AVFilterContext *filt, unsigned idx,
  220. char *name)
  221. {
  222. GraphContext *graph = gctx->priv;
  223. AVFilterPad graph_inpad =
  224. {
  225. .name = name,
  226. .type = AV_PAD_VIDEO,
  227. .start_frame = graph_in_start_frame,
  228. .end_frame = graph_in_end_frame,
  229. .get_video_buffer = graph_in_get_video_buffer,
  230. .draw_slice = graph_in_draw_slice,
  231. .config_props = graph_in_config_props,
  232. /* XXX */
  233. };
  234. AVFilterPad dummy_outpad =
  235. {
  236. .name = NULL, /* FIXME? */
  237. .type = AV_PAD_VIDEO,
  238. .request_frame = link_in_request_frame,
  239. .poll_frame = link_in_poll_frame,
  240. .config_props = link_in_config_props,
  241. };
  242. avfilter_insert_inpad (gctx, gctx->input_count, &graph_inpad);
  243. avfilter_insert_outpad(graph->link_filter_in, graph->link_filter_in->output_count,
  244. &dummy_outpad);
  245. return avfilter_link(graph->link_filter_in,
  246. graph->link_filter_in->output_count-1, filt, idx);
  247. }
  248. static int add_graph_output(AVFilterContext *gctx, AVFilterContext *filt, unsigned idx,
  249. char *name)
  250. {
  251. GraphContext *graph = gctx->priv;
  252. AVFilterPad graph_outpad =
  253. {
  254. .name = name,
  255. .type = AV_PAD_VIDEO,
  256. .request_frame = graph_out_request_frame,
  257. .poll_frame = graph_out_poll_frame,
  258. .config_props = graph_out_config_props,
  259. };
  260. AVFilterPad dummy_inpad =
  261. {
  262. .name = NULL, /* FIXME? */
  263. .type = AV_PAD_VIDEO,
  264. .start_frame = link_out_start_frame,
  265. .end_frame = link_out_end_frame,
  266. .draw_slice = link_out_draw_slice,
  267. .get_video_buffer = link_out_get_video_buffer,
  268. .config_props = link_out_config_props,
  269. };
  270. avfilter_insert_outpad(gctx, gctx->output_count, &graph_outpad);
  271. avfilter_insert_inpad (graph->link_filter_out, graph->link_filter_out->input_count,
  272. &dummy_inpad);
  273. return avfilter_link(filt, idx, graph->link_filter_out,
  274. graph->link_filter_out->input_count-1);
  275. }
  276. static void uninit(AVFilterContext *ctx)
  277. {
  278. GraphContext *graph = ctx->priv;
  279. if(graph->link_filter_in) {
  280. avfilter_destroy(graph->link_filter_in);
  281. graph->link_filter_in = NULL;
  282. }
  283. if(graph->link_filter_out) {
  284. avfilter_destroy(graph->link_filter_out);
  285. graph->link_filter_out = NULL;
  286. }
  287. for(; graph->filter_count > 0; graph->filter_count --)
  288. avfilter_destroy(graph->filters[graph->filter_count - 1]);
  289. av_freep(&graph->filters);
  290. }
  291. /* TODO: insert in sorted order */
  292. void avfilter_graph_add_filter(AVFilterContext *graphctx, AVFilterContext *filter)
  293. {
  294. GraphContext *graph = graphctx->priv;
  295. graph->filters = av_realloc(graph->filters,
  296. sizeof(AVFilterContext*) * ++graph->filter_count);
  297. graph->filters[graph->filter_count - 1] = filter;
  298. }
  299. /* search intelligently, once we insert in order */
  300. AVFilterContext *avfilter_graph_get_filter(AVFilterContext *ctx, char *name)
  301. {
  302. GraphContext *graph = ctx->priv;
  303. int i;
  304. if(!name)
  305. return NULL;
  306. for(i = 0; i < graph->filter_count; i ++)
  307. if(graph->filters[i]->name && !strcmp(name, graph->filters[i]->name))
  308. return graph->filters[i];
  309. return NULL;
  310. }
  311. static int query_formats(AVFilterContext *graphctx)
  312. {
  313. GraphContext *graph = graphctx->priv;
  314. AVFilterContext *linkfiltin = graph->link_filter_in;
  315. AVFilterContext *linkfiltout = graph->link_filter_out;
  316. int i, j;
  317. /* ask all the sub-filters for their supported colorspaces */
  318. for(i = 0; i < graph->filter_count; i ++) {
  319. if(graph->filters[i]->filter->query_formats)
  320. graph->filters[i]->filter->query_formats(graph->filters[i]);
  321. else
  322. avfilter_default_query_formats(graph->filters[i]);
  323. }
  324. /* use these formats on our exported links */
  325. for(i = 0; i < linkfiltout->input_count; i ++) {
  326. avfilter_formats_ref( linkfiltout->inputs[i]->in_formats,
  327. &linkfiltout->inputs[i]->out_formats);
  328. if(graphctx->outputs[i])
  329. avfilter_formats_ref(linkfiltout->inputs[i]->in_formats,
  330. &graphctx->outputs[i]->in_formats);
  331. }
  332. for(i = 0; i < linkfiltin->output_count; i ++) {
  333. avfilter_formats_ref( linkfiltin->outputs[i]->out_formats,
  334. &linkfiltin->outputs[i]->in_formats);
  335. if(graphctx->inputs[i])
  336. avfilter_formats_ref(linkfiltin->outputs[i]->out_formats,
  337. &graphctx-> inputs[i]->out_formats);
  338. }
  339. /* go through and merge as many format lists as possible */
  340. for(i = 0; i < graph->filter_count; i ++) {
  341. AVFilterContext *filter = graph->filters[i];
  342. for(j = 0; j < filter->input_count; j ++) {
  343. AVFilterLink *link;
  344. if(!(link = filter->inputs[j]))
  345. continue;
  346. if(link->in_formats != link->out_formats) {
  347. if(!avfilter_merge_formats(link->in_formats,
  348. link->out_formats)) {
  349. /* couldn't merge format lists. auto-insert scale filter */
  350. AVFilterContext *scale;
  351. if(!(scale = avfilter_open(&avfilter_vf_scale, NULL)))
  352. return -1;
  353. if(scale->filter->init(scale, NULL, NULL) ||
  354. avfilter_insert_filter(link, scale, 0, 0)) {
  355. avfilter_destroy(scale);
  356. return -1;
  357. }
  358. avfilter_graph_add_filter(graphctx, scale);
  359. scale->filter->query_formats(scale);
  360. if(!avfilter_merge_formats(scale-> inputs[0]->in_formats,
  361. scale-> inputs[0]->out_formats) ||
  362. !avfilter_merge_formats(scale->outputs[0]->in_formats,
  363. scale->outputs[0]->out_formats))
  364. return -1;
  365. }
  366. }
  367. }
  368. }
  369. return 0;
  370. }
  371. static void pick_format(AVFilterLink *link)
  372. {
  373. if(!link || !link->in_formats)
  374. return;
  375. link->in_formats->format_count = 1;
  376. link->format = link->in_formats->formats[0];
  377. avfilter_formats_unref(&link->in_formats);
  378. avfilter_formats_unref(&link->out_formats);
  379. }
  380. static void pick_formats(GraphContext *graph)
  381. {
  382. int i, j;
  383. for(i = 0; i < graph->filter_count; i ++) {
  384. AVFilterContext *filter = graph->filters[i];
  385. if(filter->filter == &avfilter_vf_graph ||
  386. filter->filter == &avfilter_vf_graphfile ||
  387. filter->filter == &avfilter_vf_graphdesc)
  388. pick_formats(filter->priv);
  389. for(j = 0; j < filter->input_count; j ++)
  390. pick_format(filter->inputs[j]);
  391. for(j = 0; j < filter->output_count; j ++)
  392. pick_format(filter->outputs[j]);
  393. }
  394. }
  395. int avfilter_graph_config_formats(AVFilterContext *graphctx)
  396. {
  397. GraphContext *graph = graphctx->priv;
  398. /* find supported formats from sub-filters, and merge along links */
  399. if(query_formats(graphctx))
  400. return -1;
  401. /* Once everything is merged, it's possible that we'll still have
  402. * multiple valid choices of colorspace. We pick the first one. */
  403. pick_formats(graph);
  404. return 0;
  405. }
  406. static int graph_load_from_desc(AVFilterContext *ctx, AVFilterGraphDesc *desc)
  407. {
  408. AVFilterGraphDescFilter *curfilt;
  409. AVFilterGraphDescLink *curlink;
  410. AVFilterGraphDescExport *curpad;
  411. AVFilterContext *filt, *filtb;
  412. AVFilter *filterdef;
  413. /* create all filters */
  414. for(curfilt = desc->filters; curfilt; curfilt = curfilt->next) {
  415. if(!(filterdef = avfilter_get_by_name(curfilt->filter)) ||
  416. !(filt = avfilter_open(filterdef, curfilt->name))) {
  417. av_log(ctx, AV_LOG_ERROR,
  418. "error creating filter '%s'\n", curfilt->name);
  419. goto fail;
  420. }
  421. avfilter_graph_add_filter(ctx, filt);
  422. if(avfilter_init_filter(filt, curfilt->args, NULL)) {
  423. av_log(ctx, AV_LOG_ERROR,
  424. "error initializing filter '%s'\n", curfilt->name);
  425. goto fail;
  426. }
  427. }
  428. /* create all links */
  429. for(curlink = desc->links; curlink; curlink = curlink->next) {
  430. if(!(filt = avfilter_graph_get_filter(ctx, curlink->src))) {
  431. av_log(ctx, AV_LOG_ERROR, "link source does not exist in graph\n");
  432. goto fail;
  433. }
  434. if(!(filtb = avfilter_graph_get_filter(ctx, curlink->dst))) {
  435. av_log(ctx, AV_LOG_ERROR, "link destination does not exist in graph\n");
  436. goto fail;
  437. }
  438. if(avfilter_link(filt, curlink->srcpad, filtb, curlink->dstpad)) {
  439. av_log(ctx, AV_LOG_ERROR, "cannot create link between source and destination filters\n");
  440. goto fail;
  441. }
  442. }
  443. /* export all input pads */
  444. for(curpad = desc->inputs; curpad; curpad = curpad->next) {
  445. if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
  446. av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
  447. goto fail;
  448. }
  449. add_graph_input(ctx, filt, curpad->pad, curpad->name);
  450. }
  451. /* export all output pads */
  452. for(curpad = desc->outputs; curpad; curpad = curpad->next) {
  453. if(!(filt = avfilter_graph_get_filter(ctx, curpad->filter))) {
  454. av_log(ctx, AV_LOG_ERROR, "filter owning exported pad does not exist\n");
  455. goto fail;
  456. }
  457. add_graph_output(ctx, filt, curpad->pad, curpad->name);
  458. }
  459. return 0;
  460. fail:
  461. uninit(ctx);
  462. return -1;
  463. }
  464. static int init(AVFilterContext *ctx, const char *args, void *opaque)
  465. {
  466. GraphContext *gctx = ctx->priv;
  467. AVFilterGraphDesc *desc;
  468. int ret;
  469. if(!(gctx->link_filter_in = avfilter_open(&vf_graph_dummy, NULL)))
  470. return -1;
  471. if(avfilter_init_filter(gctx->link_filter_in, NULL, ctx))
  472. goto fail;
  473. if(!(gctx->link_filter_out = avfilter_open(&vf_graph_dummy, NULL)))
  474. goto fail;
  475. if(avfilter_init_filter(gctx->link_filter_out, NULL, ctx))
  476. goto fail;
  477. if(!args)
  478. return 0;
  479. if(!(desc = avfilter_graph_parse_chain(args)))
  480. goto fail;
  481. ret = graph_load_from_desc(ctx, desc);
  482. avfilter_graph_free_desc(desc);
  483. return ret;
  484. fail:
  485. avfilter_destroy(gctx->link_filter_in);
  486. if(gctx->link_filter_out)
  487. avfilter_destroy(gctx->link_filter_out);
  488. return -1;
  489. }
  490. AVFilter avfilter_vf_graph =
  491. {
  492. .name = "graph",
  493. .author = "Bobby Bingham",
  494. .priv_size = sizeof(GraphContext),
  495. .init = init,
  496. .uninit = uninit,
  497. .query_formats = query_formats,
  498. .inputs = (AVFilterPad[]) {{ .name = NULL, }},
  499. .outputs = (AVFilterPad[]) {{ .name = NULL, }},
  500. };
  501. static int init_desc(AVFilterContext *ctx, const char *args, void *opaque)
  502. {
  503. GraphContext *gctx = ctx->priv;
  504. if(!opaque)
  505. return -1;
  506. if(!(gctx->link_filter_in = avfilter_open(&vf_graph_dummy, NULL)))
  507. return -1;
  508. if(avfilter_init_filter(gctx->link_filter_in, NULL, ctx))
  509. goto fail;
  510. if(!(gctx->link_filter_out = avfilter_open(&vf_graph_dummy, NULL)))
  511. goto fail;
  512. if(avfilter_init_filter(gctx->link_filter_out, NULL, ctx))
  513. goto fail;
  514. return graph_load_from_desc(ctx, opaque);
  515. fail:
  516. avfilter_destroy(gctx->link_filter_in);
  517. if(gctx->link_filter_out)
  518. avfilter_destroy(gctx->link_filter_out);
  519. return -1;
  520. }
  521. AVFilter avfilter_vf_graphdesc =
  522. {
  523. .name = "graph_desc",
  524. .author = "Bobby Bingham",
  525. .priv_size = sizeof(GraphContext),
  526. .init = init_desc,
  527. .uninit = uninit,
  528. .query_formats = query_formats,
  529. .inputs = (AVFilterPad[]) {{ .name = NULL, }},
  530. .outputs = (AVFilterPad[]) {{ .name = NULL, }},
  531. };
  532. static int init_file(AVFilterContext *ctx, const char *args, void *opaque)
  533. {
  534. AVFilterGraphDesc *desc;
  535. int ret;
  536. if(!args)
  537. return -1;
  538. if(!(desc = avfilter_graph_load_desc(args)))
  539. return -1;
  540. ret = init_desc(ctx, NULL, desc);
  541. avfilter_graph_free_desc(desc);
  542. return ret;
  543. }
  544. AVFilter avfilter_vf_graphfile =
  545. {
  546. .name = "graph_file",
  547. .author = "Bobby Bingham",
  548. .priv_size = sizeof(GraphContext),
  549. .init = init_file,
  550. .uninit = uninit,
  551. .query_formats = query_formats,
  552. .inputs = (AVFilterPad[]) {{ .name = NULL, }},
  553. .outputs = (AVFilterPad[]) {{ .name = NULL, }},
  554. };