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 s[4];
  34. int S[4];
  35. int d[4];
  36. int nb_planes;
  37. int back, front;
  38. Points *points;
  39. int (*is_same)(AVFrame *frame, int x, int y,
  40. unsigned s0, unsigned s1, unsigned s2, unsigned s3);
  41. void (*set_pixel)(AVFrame *frame, int x, int y,
  42. unsigned d0, unsigned d1, unsigned d2, unsigned d3);
  43. void (*pick_pixel)(AVFrame *frame, int x, int y,
  44. int *s0, int *s1, int *s2, int *s3);
  45. } FloodfillContext;
  46. static int is_inside(int x, int y, int w, int h)
  47. {
  48. if (x >= 0 && x < w && y >= 0 && y < h)
  49. return 1;
  50. return 0;
  51. }
  52. static int is_same4(AVFrame *frame, int x, int y,
  53. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  54. {
  55. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  56. unsigned c1 = frame->data[1][y * frame->linesize[1] + x];
  57. unsigned c2 = frame->data[2][y * frame->linesize[2] + x];
  58. unsigned c3 = frame->data[3][y * frame->linesize[3] + x];
  59. if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3)
  60. return 1;
  61. return 0;
  62. }
  63. static int is_same4_16(AVFrame *frame, int x, int y,
  64. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  65. {
  66. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  67. unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  68. unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  69. unsigned c3 = AV_RN16(frame->data[3] + y * frame->linesize[3] + 2 * x);
  70. if (s0 == c0 && s1 == c1 && s2 == c2 && s3 == c3)
  71. return 1;
  72. return 0;
  73. }
  74. static int is_same3(AVFrame *frame, int x, int y,
  75. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  76. {
  77. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  78. unsigned c1 = frame->data[1][y * frame->linesize[1] + x];
  79. unsigned c2 = frame->data[2][y * frame->linesize[2] + x];
  80. if (s0 == c0 && s1 == c1 && s2 == c2)
  81. return 1;
  82. return 0;
  83. }
  84. static int is_same3_16(AVFrame *frame, int x, int y,
  85. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  86. {
  87. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  88. unsigned c1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  89. unsigned c2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  90. if (s0 == c0 && s1 == c1 && s2 == c2)
  91. return 1;
  92. return 0;
  93. }
  94. static int is_same1(AVFrame *frame, int x, int y,
  95. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  96. {
  97. unsigned c0 = frame->data[0][y * frame->linesize[0] + x];
  98. if (s0 == c0)
  99. return 1;
  100. return 0;
  101. }
  102. static int is_same1_16(AVFrame *frame, int x, int y,
  103. unsigned s0, unsigned s1, unsigned s2, unsigned s3)
  104. {
  105. unsigned c0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  106. if (s0 == c0)
  107. return 1;
  108. return 0;
  109. }
  110. static void set_pixel1(AVFrame *frame, int x, int y,
  111. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  112. {
  113. frame->data[0][y * frame->linesize[0] + x] = d0;
  114. }
  115. static void set_pixel1_16(AVFrame *frame, int x, int y,
  116. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  117. {
  118. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  119. }
  120. static void set_pixel3(AVFrame *frame, int x, int y,
  121. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  122. {
  123. frame->data[0][y * frame->linesize[0] + x] = d0;
  124. frame->data[1][y * frame->linesize[1] + x] = d1;
  125. frame->data[2][y * frame->linesize[2] + x] = d2;
  126. }
  127. static void set_pixel3_16(AVFrame *frame, int x, int y,
  128. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  129. {
  130. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  131. AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1);
  132. AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2);
  133. }
  134. static void set_pixel4(AVFrame *frame, int x, int y,
  135. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  136. {
  137. frame->data[0][y * frame->linesize[0] + x] = d0;
  138. frame->data[1][y * frame->linesize[1] + x] = d1;
  139. frame->data[2][y * frame->linesize[2] + x] = d2;
  140. frame->data[3][y * frame->linesize[3] + x] = d3;
  141. }
  142. static void set_pixel4_16(AVFrame *frame, int x, int y,
  143. unsigned d0, unsigned d1, unsigned d2, unsigned d3)
  144. {
  145. AV_WN16(frame->data[0] + y * frame->linesize[0] + 2 * x, d0);
  146. AV_WN16(frame->data[1] + y * frame->linesize[1] + 2 * x, d1);
  147. AV_WN16(frame->data[2] + y * frame->linesize[2] + 2 * x, d2);
  148. AV_WN16(frame->data[3] + y * frame->linesize[3] + 2 * x, d3);
  149. }
  150. static void pick_pixel1(AVFrame *frame, int x, int y,
  151. int *s0, int *s1, int *s2, int *s3)
  152. {
  153. if (*s0 < 0)
  154. *s0 = frame->data[0][y * frame->linesize[0] + x];
  155. }
  156. static void pick_pixel1_16(AVFrame *frame, int x, int y,
  157. int *s0, int *s1, int *s2, int *s3)
  158. {
  159. if (*s0 < 0)
  160. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  161. }
  162. static void pick_pixel3(AVFrame *frame, int x, int y,
  163. int *s0, int *s1, int *s2, int *s3)
  164. {
  165. if (*s0 < 0)
  166. *s0 = frame->data[0][y * frame->linesize[0] + x];
  167. if (*s1 < 0)
  168. *s1 = frame->data[1][y * frame->linesize[1] + x];
  169. if (*s2 < 0)
  170. *s2 = frame->data[2][y * frame->linesize[2] + x];
  171. }
  172. static void pick_pixel3_16(AVFrame *frame, int x, int y,
  173. int *s0, int *s1, int *s2, int *s3)
  174. {
  175. if (*s0 < 0)
  176. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  177. if (*s1 < 0)
  178. *s1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  179. if (*s2 < 0)
  180. *s2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  181. }
  182. static void pick_pixel4(AVFrame *frame, int x, int y,
  183. int *s0, int *s1, int *s2, int *s3)
  184. {
  185. if (*s0 < 0)
  186. *s0 = frame->data[0][y * frame->linesize[0] + x];
  187. if (*s1 < 0)
  188. *s1 = frame->data[1][y * frame->linesize[1] + x];
  189. if (*s2 < 0)
  190. *s2 = frame->data[2][y * frame->linesize[2] + x];
  191. if (*s3 < 0)
  192. *s3 = frame->data[3][y * frame->linesize[3] + x];
  193. }
  194. static void pick_pixel4_16(AVFrame *frame, int x, int y,
  195. int *s0, int *s1, int *s2, int *s3)
  196. {
  197. if (*s0 < 0)
  198. *s0 = AV_RN16(frame->data[0] + y * frame->linesize[0] + 2 * x);
  199. if (*s1 < 0)
  200. *s1 = AV_RN16(frame->data[1] + y * frame->linesize[1] + 2 * x);
  201. if (*s2 < 0)
  202. *s2 = AV_RN16(frame->data[2] + y * frame->linesize[2] + 2 * x);
  203. if (*s3 < 0)
  204. *s3 = AV_RN16(frame->data[3] + y * frame->linesize[3] + 2 * x);
  205. }
  206. static int config_input(AVFilterLink *inlink)
  207. {
  208. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  209. AVFilterContext *ctx = inlink->dst;
  210. FloodfillContext *s = ctx->priv;
  211. int depth;
  212. s->nb_planes = av_pix_fmt_count_planes(inlink->format);
  213. depth = desc->comp[0].depth;
  214. if (depth == 8) {
  215. switch (s->nb_planes) {
  216. case 1: s->set_pixel = set_pixel1;
  217. s->is_same = is_same1;
  218. s->pick_pixel = pick_pixel1; break;
  219. case 3: s->set_pixel = set_pixel3;
  220. s->is_same = is_same3;
  221. s->pick_pixel = pick_pixel3; break;
  222. case 4: s->set_pixel = set_pixel4;
  223. s->is_same = is_same4;
  224. s->pick_pixel = pick_pixel4; break;
  225. }
  226. } else {
  227. switch (s->nb_planes) {
  228. case 1: s->set_pixel = set_pixel1_16;
  229. s->is_same = is_same1_16;
  230. s->pick_pixel = pick_pixel1_16; break;
  231. case 3: s->set_pixel = set_pixel3_16;
  232. s->is_same = is_same3_16;
  233. s->pick_pixel = pick_pixel3_16; break;
  234. case 4: s->set_pixel = set_pixel4_16;
  235. s->is_same = is_same4_16;
  236. s->pick_pixel = pick_pixel4_16; break;
  237. }
  238. }
  239. s->front = s->back = 0;
  240. s->points = av_calloc(inlink->w * inlink->h, 4 * sizeof(Points));
  241. if (!s->points)
  242. return AVERROR(ENOMEM);
  243. return 0;
  244. }
  245. static int filter_frame(AVFilterLink *link, AVFrame *frame)
  246. {
  247. AVFilterContext *ctx = link->dst;
  248. FloodfillContext *s = ctx->priv;
  249. const unsigned d0 = s->d[0];
  250. const unsigned d1 = s->d[1];
  251. const unsigned d2 = s->d[2];
  252. const unsigned d3 = s->d[3];
  253. int s0 = s->s[0];
  254. int s1 = s->s[1];
  255. int s2 = s->s[2];
  256. int s3 = s->s[3];
  257. const int w = frame->width;
  258. const int h = frame->height;
  259. int i, 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. s->S[0] = s0;
  263. s->S[1] = s1;
  264. s->S[2] = s2;
  265. s->S[3] = s3;
  266. for (i = 0; i < s->nb_planes; i++) {
  267. if (s->S[i] != s->d[i])
  268. break;
  269. }
  270. if (i == s->nb_planes)
  271. goto end;
  272. if (s->is_same(frame, s->x, s->y, s0, s1, s2, s3)) {
  273. s->points[s->front].x = s->x;
  274. s->points[s->front].y = s->y;
  275. s->front++;
  276. }
  277. if (ret = av_frame_make_writable(frame))
  278. return ret;
  279. while (s->front > s->back) {
  280. int x, y;
  281. s->front--;
  282. x = s->points[s->front].x;
  283. y = s->points[s->front].y;
  284. if (s->is_same(frame, x, y, s0, s1, s2, s3)) {
  285. s->set_pixel(frame, x, y, d0, d1, d2, d3);
  286. if (is_inside(x + 1, y, w, h)) {
  287. s->points[s->front] .x = x + 1;
  288. s->points[s->front++].y = y;
  289. }
  290. if (is_inside(x - 1, y, w, h)) {
  291. s->points[s->front] .x = x - 1;
  292. s->points[s->front++].y = y;
  293. }
  294. if (is_inside(x, y + 1, w, h)) {
  295. s->points[s->front] .x = x;
  296. s->points[s->front++].y = y + 1;
  297. }
  298. if (is_inside(x, y - 1, w, h)) {
  299. s->points[s->front] .x = x;
  300. s->points[s->front++].y = y - 1;
  301. }
  302. }
  303. }
  304. }
  305. end:
  306. return ff_filter_frame(ctx->outputs[0], frame);
  307. }
  308. static av_cold int query_formats(AVFilterContext *ctx)
  309. {
  310. static const enum AVPixelFormat pixel_fmts[] = {
  311. AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
  312. AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P,
  313. AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
  314. AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
  315. AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GBRAP,
  316. AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
  317. AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16,
  318. AV_PIX_FMT_NONE
  319. };
  320. AVFilterFormats *formats;
  321. formats = ff_make_format_list(pixel_fmts);
  322. if (!formats)
  323. return AVERROR(ENOMEM);
  324. return ff_set_common_formats(ctx, formats);
  325. }
  326. static av_cold void uninit(AVFilterContext *ctx)
  327. {
  328. FloodfillContext *s = ctx->priv;
  329. av_freep(&s->points);
  330. }
  331. static const AVFilterPad floodfill_inputs[] = {
  332. {
  333. .name = "default",
  334. .type = AVMEDIA_TYPE_VIDEO,
  335. .filter_frame = filter_frame,
  336. .config_props = config_input,
  337. },
  338. { NULL }
  339. };
  340. static const AVFilterPad floodfill_outputs[] = {
  341. {
  342. .name = "default",
  343. .type = AVMEDIA_TYPE_VIDEO,
  344. },
  345. { NULL }
  346. };
  347. #define OFFSET(x) offsetof(FloodfillContext, x)
  348. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  349. static const AVOption floodfill_options[] = {
  350. { "x", "set pixel x coordinate", OFFSET(x), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  351. { "y", "set pixel y coordinate", OFFSET(y), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  352. { "s0", "set source #0 component value", OFFSET(s[0]), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  353. { "s1", "set source #1 component value", OFFSET(s[1]), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  354. { "s2", "set source #2 component value", OFFSET(s[2]), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  355. { "s3", "set source #3 component value", OFFSET(s[3]), AV_OPT_TYPE_INT, {.i64=0},-1, UINT16_MAX, FLAGS },
  356. { "d0", "set destination #0 component value", OFFSET(d[0]), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  357. { "d1", "set destination #1 component value", OFFSET(d[1]), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  358. { "d2", "set destination #2 component value", OFFSET(d[2]), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  359. { "d3", "set destination #3 component value", OFFSET(d[3]), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, FLAGS },
  360. { NULL }
  361. };
  362. AVFILTER_DEFINE_CLASS(floodfill);
  363. AVFilter ff_vf_floodfill = {
  364. .name = "floodfill",
  365. .description = NULL_IF_CONFIG_SMALL("Fill area with same color with another color."),
  366. .priv_size = sizeof(FloodfillContext),
  367. .priv_class = &floodfill_class,
  368. .query_formats = query_formats,
  369. .uninit = uninit,
  370. .inputs = floodfill_inputs,
  371. .outputs = floodfill_outputs,
  372. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
  373. };