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.

434 lines
14KB

  1. /*
  2. * Copyright (c) 2017 Paul B Mahol
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "libavutil/opt.h"
  21. #include "libavutil/imgutils.h"
  22. #include "libavutil/intreadwrite.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "internal.h"
  26. #include "video.h"
  27. typedef struct Points {
  28. uint16_t x, y;
  29. } Points;
  30. typedef struct FloodfillContext {
  31. const AVClass *class;
  32. int x, y;
  33. int s0, s1, s2, s3;
  34. int d0, d1, d2, d3;
  35. int back, front;
  36. Points *points;
  37. int (*is_same)(AVFrame *frame, int x, int y,
  38. unsigned s0, unsigned s1, unsigned s2, unsigned s3);
  39. void (*set_pixel)(AVFrame *frame, int x, int y,
  40. unsigned d0, unsigned d1, unsigned d2, unsigned d3);
  41. void (*pick_pixel)(AVFrame *frame, int x, int y,
  42. int *s0, int *s1, int *s2, int *s3);
  43. } FloodfillContext;
  44. static int is_inside(int x, int y, int w, int h)
  45. {
  46. if (x >= 0 && x < w && y >= 0 && y < h)
  47. return 1;
  48. return 0;
  49. }
  50. static int is_same4(AVFrame *frame, int x, int y,
  51. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  52. {
  53. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  54. unsigned c1 = frame->data[1][y * frame->linesize[1] + x];
  55. unsigned c2 = frame->data[2][y * frame->linesize[2] + x];
  56. unsigned c3 = frame->data[3][y * frame->linesize[3] + x];
  57. if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3)
  58. return 1;
  59. return 0;
  60. }
  61. static int is_same4_16(AVFrame *frame, int x, int y,
  62. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  63. {
  64. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  65. unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  66. unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  67. unsigned c3 = AV_RN16(frame->data[3] + y * frame->linesize[3] + 2 * x);
  68. if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3)
  69. return 1;
  70. return 0;
  71. }
  72. static int is_same3(AVFrame *frame, int x, int y,
  73. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  74. {
  75. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  76. unsigned c1 = frame->data[1][y * frame->linesize[1] + x];
  77. unsigned c2 = frame->data[2][y * frame->linesize[2] + x];
  78. if (s0 == c0 && s1 == c1 && s2 == c2)
  79. return 1;
  80. return 0;
  81. }
  82. static int is_same3_16(AVFrame *frame, int x, int y,
  83. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  84. {
  85. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  86. unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  87. unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  88. if (s0 == c0 && s1 == c1 && s2 == c2)
  89. return 1;
  90. return 0;
  91. }
  92. static int is_same1(AVFrame *frame, int x, int y,
  93. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  94. {
  95. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  96. if (s0 == c0)
  97. return 1;
  98. return 0;
  99. }
  100. static int is_same1_16(AVFrame *frame, int x, int y,
  101. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  102. {
  103. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  104. if (s0 == c0)
  105. return 1;
  106. return 0;
  107. }
  108. static void set_pixel1(AVFrame *frame, int x, int y,
  109. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  110. {
  111. frame->data[0][y * frame->linesize[0] + x] = d0;
  112. }
  113. static void set_pixel1_16(AVFrame *frame, int x, int y,
  114. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  115. {
  116. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  117. }
  118. static void set_pixel3(AVFrame *frame, int x, int y,
  119. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  120. {
  121. frame->data[0][y * frame->linesize[0] + x] = d0;
  122. frame->data[1][y * frame->linesize[1] + x] = d1;
  123. frame->data[2][y * frame->linesize[2] + x] = d2;
  124. }
  125. static void set_pixel3_16(AVFrame *frame, int x, int y,
  126. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  127. {
  128. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  129. AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1);
  130. AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2);
  131. }
  132. static void set_pixel4(AVFrame *frame, int x, int y,
  133. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  134. {
  135. frame->data[0][y * frame->linesize[0] + x] = d0;
  136. frame->data[1][y * frame->linesize[1] + x] = d1;
  137. frame->data[2][y * frame->linesize[2] + x] = d2;
  138. frame->data[3][y * frame->linesize[3] + x] = d3;
  139. }
  140. static void set_pixel4_16(AVFrame *frame, int x, int y,
  141. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  142. {
  143. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  144. AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1);
  145. AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2);
  146. AV_WN16(frame->data[3] + y * frame->linesize[3] + 2 * x, d3);
  147. }
  148. static void pick_pixel1(AVFrame *frame, int x, int y,
  149. int *s0, int *s1, int *s2, int *s3)
  150. {
  151. if (*s0 < 0)
  152. *s0 = frame->data[0][y * frame->linesize[0] + x];
  153. }
  154. static void pick_pixel1_16(AVFrame *frame, int x, int y,
  155. int *s0, int *s1, int *s2, int *s3)
  156. {
  157. if (*s0 < 0)
  158. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  159. }
  160. static void pick_pixel3(AVFrame *frame, int x, int y,
  161. int *s0, int *s1, int *s2, int *s3)
  162. {
  163. if (*s0 < 0)
  164. *s0 = frame->data[0][y * frame->linesize[0] + x];
  165. if (*s1 < 0)
  166. *s1 = frame->data[1][y * frame->linesize[1] + x];
  167. if (*s2 < 0)
  168. *s2 = frame->data[2][y * frame->linesize[2] + x];
  169. }
  170. static void pick_pixel3_16(AVFrame *frame, int x, int y,
  171. int *s0, int *s1, int *s2, int *s3)
  172. {
  173. if (*s0 < 0)
  174. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  175. if (*s1 < 0)
  176. *s1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  177. if (*s2 < 0)
  178. *s2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  179. }
  180. static void pick_pixel4(AVFrame *frame, int x, int y,
  181. int *s0, int *s1, int *s2, int *s3)
  182. {
  183. if (*s0 < 0)
  184. *s0 = frame->data[0][y * frame->linesize[0] + x];
  185. if (*s1 < 0)
  186. *s1 = frame->data[1][y * frame->linesize[1] + x];
  187. if (*s2 < 0)
  188. *s2 = frame->data[2][y * frame->linesize[2] + x];
  189. if (*s3 < 0)
  190. *s3 = frame->data[3][y * frame->linesize[3] + x];
  191. }
  192. static void pick_pixel4_16(AVFrame *frame, int x, int y,
  193. int *s0, int *s1, int *s2, int *s3)
  194. {
  195. if (*s0 < 0)
  196. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  197. if (*s1 < 0)
  198. *s1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  199. if (*s2 < 0)
  200. *s2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  201. if (*s3 < 0)
  202. *s3 = AV_RN16(frame->data[3] + y * frame->linesize[3] + 2 * x);
  203. }
  204. static int config_input(AVFilterLink *inlink)
  205. {
  206. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  207. AVFilterContext *ctx = inlink->dst;
  208. FloodfillContext *s = ctx->priv;
  209. int nb_planes = av_pix_fmt_count_planes(inlink->format);
  210. int depth;
  211. depth = desc->comp[0].depth;
  212. if (depth == 8) {
  213. switch (nb_planes) {
  214. case 1: s->set_pixel = set_pixel1;
  215. s->is_same = is_same1;
  216. s->pick_pixel = pick_pixel1; break;
  217. case 3: s->set_pixel = set_pixel3;
  218. s->is_same = is_same3;
  219. s->pick_pixel = pick_pixel3; break;
  220. case 4: s->set_pixel = set_pixel4;
  221. s->is_same = is_same4;
  222. s->pick_pixel = pick_pixel4; break;
  223. }
  224. } else {
  225. switch (nb_planes) {
  226. case 1: s->set_pixel = set_pixel1_16;
  227. s->is_same = is_same1_16;
  228. s->pick_pixel = pick_pixel1_16; break;
  229. case 3: s->set_pixel = set_pixel3_16;
  230. s->is_same = is_same3_16;
  231. s->pick_pixel = pick_pixel3_16; break;
  232. case 4: s->set_pixel = set_pixel4_16;
  233. s->is_same = is_same4_16;
  234. s->pick_pixel = pick_pixel4_16; break;
  235. }
  236. }
  237. s->front = s->back = 0;
  238. s->points = av_calloc(inlink->w * inlink->h, 4 * sizeof(Points));
  239. if (!s->points)
  240. return AVERROR(ENOMEM);
  241. return 0;
  242. }
  243. static int filter_frame(AVFilterLink *link, AVFrame *frame)
  244. {
  245. AVFilterContext *ctx = link->dst;
  246. FloodfillContext *s = ctx->priv;
  247. const unsigned d0 = s->d0;
  248. const unsigned d1 = s->d1;
  249. const unsigned d2 = s->d2;
  250. const unsigned d3 = s->d3;
  251. int s0 = s->s0;
  252. int s1 = s->s1;
  253. int s2 = s->s2;
  254. int s3 = s->s3;
  255. const int w = frame->width;
  256. const int h = frame->height;
  257. int ret;
  258. if (ret = av_frame_make_writable(frame))
  259. return ret;
  260. if (is_inside(s->x, s->y, w, h)) {
  261. s->pick_pixel(frame, s->x, s->y, &s0, &s1, &s2, &s3);
  262. if (s->is_same(frame, s->x, s->y, s0, s1, s2, s3)) {
  263. s->points[s->front].x = s->x;
  264. s->points[s->front].y = s->y;
  265. s->front++;
  266. }
  267. while (s->front > s->back) {
  268. int x, y;
  269. s->front--;
  270. x = s->points[s->front].x;
  271. y = s->points[s->front].y;
  272. if (s->is_same(frame, x, y, s0, s1, s2, s3)) {
  273. s->set_pixel(frame, x, y, d0, d1, d2, d3);
  274. if (is_inside(x + 1, y, w, h)) {
  275. s->points[s->front] .x = x + 1;
  276. s->points[s->front++].y = y;
  277. }
  278. if (is_inside(x - 1, y, w, h)) {
  279. s->points[s->front] .x = x - 1;
  280. s->points[s->front++].y = y;
  281. }
  282. if (is_inside(x, y + 1, w, h)) {
  283. s->points[s->front] .x = x;
  284. s->points[s->front++].y = y + 1;
  285. }
  286. if (is_inside(x, y - 1, w, h)) {
  287. s->points[s->front] .x = x;
  288. s->points[s->front++].y = y - 1;
  289. }
  290. }
  291. }
  292. }
  293. return ff_filter_frame(ctx->outputs[0], frame);
  294. }
  295. static av_cold int query_formats(AVFilterContext *ctx)
  296. {
  297. static const enum AVPixelFormat pixel_fmts[] = {
  298. AV_PIX_FMT_GRAY8,
  299. AV_PIX_FMT_YUV444P,
  300. AV_PIX_FMT_YUVA444P,
  301. AV_PIX_FMT_GBRP,
  302. AV_PIX_FMT_GBRP9,
  303. AV_PIX_FMT_GBRP10,
  304. AV_PIX_FMT_GBRAP10,
  305. AV_PIX_FMT_GBRP12,
  306. AV_PIX_FMT_GBRAP12,
  307. AV_PIX_FMT_GBRP14,
  308. AV_PIX_FMT_GBRP16,
  309. AV_PIX_FMT_GBRAP16,
  310. AV_PIX_FMT_GBRAP,
  311. AV_PIX_FMT_YUV444P9,
  312. AV_PIX_FMT_YUVA444P9,
  313. AV_PIX_FMT_YUV444P10,
  314. AV_PIX_FMT_YUVA444P10,
  315. AV_PIX_FMT_YUV444P12,
  316. AV_PIX_FMT_YUV444P14,
  317. AV_PIX_FMT_GRAY16,
  318. AV_PIX_FMT_YUV444P16,
  319. AV_PIX_FMT_YUVA444P16,
  320. AV_PIX_FMT_NONE
  321. };
  322. AVFilterFormats *formats;
  323. formats = ff_make_format_list(pixel_fmts);
  324. if (!formats)
  325. return AVERROR(ENOMEM);
  326. return ff_set_common_formats(ctx, formats);
  327. }
  328. static av_cold void uninit(AVFilterContext *ctx)
  329. {
  330. FloodfillContext *s = ctx->priv;
  331. av_freep(&s->points);
  332. }
  333. static const AVFilterPad floodfill_inputs[] = {
  334. {
  335. .name = "default",
  336. .type = AVMEDIA_TYPE_VIDEO,
  337. .filter_frame = filter_frame,
  338. .config_props = config_input,
  339. },
  340. { NULL }
  341. };
  342. static const AVFilterPad floodfill_outputs[] = {
  343. {
  344. .name = "default",
  345. .type = AVMEDIA_TYPE_VIDEO,
  346. },
  347. { NULL }
  348. };
  349. #define OFFSET(x) offsetof(FloodfillContext, x)
  350. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  351. static const AVOption floodfill_options[] = {
  352. { "x", "set pixel x coordinate", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  353. { "y", "set pixel y coordinate", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  354. { "s0", "set source #0 component value", OFFSET(s0), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  355. { "s1", "set source #1 component value", OFFSET(s1), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  356. { "s2", "set source #2 component value", OFFSET(s2), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  357. { "s3", "set source #3 component value", OFFSET(s3), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  358. { "d0", "set destination #0 component value", OFFSET(d0), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  359. { "d1", "set destination #1 component value", OFFSET(d1), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  360. { "d2", "set destination #2 component value", OFFSET(d2), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  361. { "d3", "set destination #3 component value", OFFSET(d3), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  362. { NULL }
  363. };
  364. AVFILTER_DEFINE_CLASS(floodfill);
  365. AVFilter ff_vf_floodfill = {
  366. .name = "floodfill",
  367. .description = NULL_IF_CONFIG_SMALL("Fill area with same color with another color."),
  368. .priv_size = sizeof(FloodfillContext),
  369. .priv_class = &floodfill_class,
  370. .query_formats = query_formats,
  371. .uninit = uninit,
  372. .inputs = floodfill_inputs,
  373. .outputs = floodfill_outputs,
  374. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
  375. };