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.

397 lines
13KB

  1. /*
  2. * Copyright (c) 2013 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/imgutils.h"
  21. #include "libavutil/pixdesc.h"
  22. #include "libavutil/opt.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "framesync.h"
  26. #include "internal.h"
  27. #include "video.h"
  28. enum EdgeMode {
  29. EDGE_BLANK,
  30. EDGE_SMEAR,
  31. EDGE_WRAP,
  32. EDGE_NB
  33. };
  34. typedef struct DisplaceContext {
  35. const AVClass *class;
  36. int width[4], height[4];
  37. enum EdgeMode edge;
  38. int nb_planes;
  39. int nb_components;
  40. int step;
  41. uint8_t blank[4];
  42. FFFrameSync fs;
  43. void (*displace)(struct DisplaceContext *s, const AVFrame *in,
  44. const AVFrame *xpic, const AVFrame *ypic, AVFrame *out);
  45. } DisplaceContext;
  46. #define OFFSET(x) offsetof(DisplaceContext, x)
  47. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
  48. static const AVOption displace_options[] = {
  49. { "edge", "set edge mode", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=EDGE_SMEAR}, 0, EDGE_NB-1, FLAGS, "edge" },
  50. { "blank", "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_BLANK}, 0, 0, FLAGS, "edge" },
  51. { "smear", "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_SMEAR}, 0, 0, FLAGS, "edge" },
  52. { "wrap" , "", 0, AV_OPT_TYPE_CONST, {.i64=EDGE_WRAP}, 0, 0, FLAGS, "edge" },
  53. { NULL }
  54. };
  55. AVFILTER_DEFINE_CLASS(displace);
  56. static int query_formats(AVFilterContext *ctx)
  57. {
  58. static const enum AVPixelFormat pix_fmts[] = {
  59. AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
  60. AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
  61. AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P,
  62. AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
  63. AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
  64. AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
  65. AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA,
  66. AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0,
  67. AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
  68. AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
  69. };
  70. ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
  71. return 0;
  72. }
  73. static void displace_planar(DisplaceContext *s, const AVFrame *in,
  74. const AVFrame *xpic, const AVFrame *ypic,
  75. AVFrame *out)
  76. {
  77. int plane, x, y;
  78. for (plane = 0; plane < s->nb_planes; plane++) {
  79. const int h = s->height[plane];
  80. const int w = s->width[plane];
  81. const int dlinesize = out->linesize[plane];
  82. const int slinesize = in->linesize[plane];
  83. const int xlinesize = xpic->linesize[plane];
  84. const int ylinesize = ypic->linesize[plane];
  85. const uint8_t *src = in->data[plane];
  86. const uint8_t *ysrc = ypic->data[plane];
  87. const uint8_t *xsrc = xpic->data[plane];
  88. uint8_t *dst = out->data[plane];
  89. const uint8_t blank = s->blank[plane];
  90. for (y = 0; y < h; y++) {
  91. switch (s->edge) {
  92. case EDGE_BLANK:
  93. for (x = 0; x < w; x++) {
  94. int Y = y + ysrc[x] - 128;
  95. int X = x + xsrc[x] - 128;
  96. if (Y < 0 || Y >= h || X < 0 || X >= w)
  97. dst[x] = blank;
  98. else
  99. dst[x] = src[Y * slinesize + X];
  100. }
  101. break;
  102. case EDGE_SMEAR:
  103. for (x = 0; x < w; x++) {
  104. int Y = av_clip(y + ysrc[x] - 128, 0, h - 1);
  105. int X = av_clip(x + xsrc[x] - 128, 0, w - 1);
  106. dst[x] = src[Y * slinesize + X];
  107. }
  108. break;
  109. case EDGE_WRAP:
  110. for (x = 0; x < w; x++) {
  111. int Y = (y + ysrc[x] - 128) % h;
  112. int X = (x + xsrc[x] - 128) % w;
  113. if (Y < 0)
  114. Y += h;
  115. if (X < 0)
  116. X += w;
  117. dst[x] = src[Y * slinesize + X];
  118. }
  119. break;
  120. }
  121. ysrc += ylinesize;
  122. xsrc += xlinesize;
  123. dst += dlinesize;
  124. }
  125. }
  126. }
  127. static void displace_packed(DisplaceContext *s, const AVFrame *in,
  128. const AVFrame *xpic, const AVFrame *ypic,
  129. AVFrame *out)
  130. {
  131. const int step = s->step;
  132. const int h = s->height[0];
  133. const int w = s->width[0];
  134. const int dlinesize = out->linesize[0];
  135. const int slinesize = in->linesize[0];
  136. const int xlinesize = xpic->linesize[0];
  137. const int ylinesize = ypic->linesize[0];
  138. const uint8_t *src = in->data[0];
  139. const uint8_t *ysrc = ypic->data[0];
  140. const uint8_t *xsrc = xpic->data[0];
  141. const uint8_t *blank = s->blank;
  142. uint8_t *dst = out->data[0];
  143. int c, x, y;
  144. for (y = 0; y < h; y++) {
  145. switch (s->edge) {
  146. case EDGE_BLANK:
  147. for (x = 0; x < w; x++) {
  148. for (c = 0; c < s->nb_components; c++) {
  149. int Y = y + (ysrc[x * step + c] - 128);
  150. int X = x + (xsrc[x * step + c] - 128);
  151. if (Y < 0 || Y >= h || X < 0 || X >= w)
  152. dst[x * step + c] = blank[c];
  153. else
  154. dst[x * step + c] = src[Y * slinesize + X * step + c];
  155. }
  156. }
  157. break;
  158. case EDGE_SMEAR:
  159. for (x = 0; x < w; x++) {
  160. for (c = 0; c < s->nb_components; c++) {
  161. int Y = av_clip(y + (ysrc[x * step + c] - 128), 0, h - 1);
  162. int X = av_clip(x + (xsrc[x * step + c] - 128), 0, w - 1);
  163. dst[x * step + c] = src[Y * slinesize + X * step + c];
  164. }
  165. }
  166. break;
  167. case EDGE_WRAP:
  168. for (x = 0; x < w; x++) {
  169. for (c = 0; c < s->nb_components; c++) {
  170. int Y = (y + (ysrc[x * step + c] - 128)) % h;
  171. int X = (x + (xsrc[x * step + c] - 128)) % w;
  172. if (Y < 0)
  173. Y += h;
  174. if (X < 0)
  175. X += w;
  176. dst[x * step + c] = src[Y * slinesize + X * step + c];
  177. }
  178. }
  179. break;
  180. }
  181. ysrc += ylinesize;
  182. xsrc += xlinesize;
  183. dst += dlinesize;
  184. }
  185. }
  186. static int process_frame(FFFrameSync *fs)
  187. {
  188. AVFilterContext *ctx = fs->parent;
  189. DisplaceContext *s = fs->opaque;
  190. AVFilterLink *outlink = ctx->outputs[0];
  191. AVFrame *out, *in, *xpic, *ypic;
  192. int ret;
  193. if ((ret = ff_framesync_get_frame(&s->fs, 0, &in, 0)) < 0 ||
  194. (ret = ff_framesync_get_frame(&s->fs, 1, &xpic, 0)) < 0 ||
  195. (ret = ff_framesync_get_frame(&s->fs, 2, &ypic, 0)) < 0)
  196. return ret;
  197. if (ctx->is_disabled) {
  198. out = av_frame_clone(in);
  199. if (!out)
  200. return AVERROR(ENOMEM);
  201. } else {
  202. out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  203. if (!out)
  204. return AVERROR(ENOMEM);
  205. av_frame_copy_props(out, in);
  206. s->displace(s, in, xpic, ypic, out);
  207. }
  208. out->pts = av_rescale_q(in->pts, s->fs.time_base, outlink->time_base);
  209. return ff_filter_frame(outlink, out);
  210. }
  211. static int config_input(AVFilterLink *inlink)
  212. {
  213. AVFilterContext *ctx = inlink->dst;
  214. DisplaceContext *s = ctx->priv;
  215. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  216. int vsub, hsub;
  217. s->nb_planes = av_pix_fmt_count_planes(inlink->format);
  218. s->nb_components = desc->nb_components;
  219. if (s->nb_planes > 1 || s->nb_components == 1)
  220. s->displace = displace_planar;
  221. else
  222. s->displace = displace_packed;
  223. if (!(desc->flags & AV_PIX_FMT_FLAG_RGB)) {
  224. s->blank[1] = s->blank[2] = 128;
  225. s->blank[0] = 16;
  226. }
  227. s->step = av_get_padded_bits_per_pixel(desc) >> 3;
  228. hsub = desc->log2_chroma_w;
  229. vsub = desc->log2_chroma_h;
  230. s->height[1] = s->height[2] = FF_CEIL_RSHIFT(inlink->h, vsub);
  231. s->height[0] = s->height[3] = inlink->h;
  232. s->width[1] = s->width[2] = FF_CEIL_RSHIFT(inlink->w, hsub);
  233. s->width[0] = s->width[3] = inlink->w;
  234. return 0;
  235. }
  236. static int config_output(AVFilterLink *outlink)
  237. {
  238. AVFilterContext *ctx = outlink->src;
  239. DisplaceContext *s = ctx->priv;
  240. AVFilterLink *srclink = ctx->inputs[0];
  241. AVFilterLink *xlink = ctx->inputs[1];
  242. AVFilterLink *ylink = ctx->inputs[2];
  243. FFFrameSyncIn *in;
  244. int ret;
  245. if (srclink->format != xlink->format ||
  246. srclink->format != ylink->format) {
  247. av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n");
  248. return AVERROR(EINVAL);
  249. }
  250. if (srclink->w != xlink->w ||
  251. srclink->h != xlink->h ||
  252. srclink->sample_aspect_ratio.num != xlink->sample_aspect_ratio.num ||
  253. srclink->sample_aspect_ratio.den != xlink->sample_aspect_ratio.den ||
  254. srclink->w != ylink->w ||
  255. srclink->h != ylink->h ||
  256. srclink->sample_aspect_ratio.num != ylink->sample_aspect_ratio.num ||
  257. srclink->sample_aspect_ratio.den != ylink->sample_aspect_ratio.den) {
  258. av_log(ctx, AV_LOG_ERROR, "First input link %s parameters "
  259. "(size %dx%d, SAR %d:%d) do not match the corresponding "
  260. "second input link %s parameters (%dx%d, SAR %d:%d) "
  261. "and/or third input link %s parameters (%dx%d, SAR %d:%d)\n",
  262. ctx->input_pads[0].name, srclink->w, srclink->h,
  263. srclink->sample_aspect_ratio.num,
  264. srclink->sample_aspect_ratio.den,
  265. ctx->input_pads[1].name, xlink->w, xlink->h,
  266. xlink->sample_aspect_ratio.num,
  267. xlink->sample_aspect_ratio.den,
  268. ctx->input_pads[2].name, ylink->w, ylink->h,
  269. ylink->sample_aspect_ratio.num,
  270. ylink->sample_aspect_ratio.den);
  271. return AVERROR(EINVAL);
  272. }
  273. outlink->w = srclink->w;
  274. outlink->h = srclink->h;
  275. outlink->time_base = srclink->time_base;
  276. outlink->sample_aspect_ratio = srclink->sample_aspect_ratio;
  277. outlink->frame_rate = srclink->frame_rate;
  278. ret = ff_framesync_init(&s->fs, ctx, 3);
  279. if (ret < 0)
  280. return ret;
  281. in = s->fs.in;
  282. in[0].time_base = srclink->time_base;
  283. in[1].time_base = xlink->time_base;
  284. in[2].time_base = ylink->time_base;
  285. in[0].sync = 2;
  286. in[0].before = EXT_STOP;
  287. in[0].after = EXT_STOP;
  288. in[1].sync = 1;
  289. in[1].before = EXT_NULL;
  290. in[1].after = EXT_INFINITY;
  291. in[2].sync = 1;
  292. in[2].before = EXT_NULL;
  293. in[2].after = EXT_INFINITY;
  294. s->fs.opaque = s;
  295. s->fs.on_event = process_frame;
  296. return ff_framesync_configure(&s->fs);
  297. }
  298. static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
  299. {
  300. DisplaceContext *s = inlink->dst->priv;
  301. return ff_framesync_filter_frame(&s->fs, inlink, buf);
  302. }
  303. static int request_frame(AVFilterLink *outlink)
  304. {
  305. DisplaceContext *s = outlink->src->priv;
  306. return ff_framesync_request_frame(&s->fs, outlink);
  307. }
  308. static av_cold void uninit(AVFilterContext *ctx)
  309. {
  310. DisplaceContext *s = ctx->priv;
  311. ff_framesync_uninit(&s->fs);
  312. }
  313. static const AVFilterPad displace_inputs[] = {
  314. {
  315. .name = "source",
  316. .type = AVMEDIA_TYPE_VIDEO,
  317. .filter_frame = filter_frame,
  318. .config_props = config_input,
  319. },
  320. {
  321. .name = "xmap",
  322. .type = AVMEDIA_TYPE_VIDEO,
  323. .filter_frame = filter_frame,
  324. },
  325. {
  326. .name = "ymap",
  327. .type = AVMEDIA_TYPE_VIDEO,
  328. .filter_frame = filter_frame,
  329. },
  330. { NULL }
  331. };
  332. static const AVFilterPad displace_outputs[] = {
  333. {
  334. .name = "default",
  335. .type = AVMEDIA_TYPE_VIDEO,
  336. .config_props = config_output,
  337. .request_frame = request_frame,
  338. },
  339. { NULL }
  340. };
  341. AVFilter ff_vf_displace = {
  342. .name = "displace",
  343. .description = NULL_IF_CONFIG_SMALL("Displace pixels."),
  344. .priv_size = sizeof(DisplaceContext),
  345. .uninit = uninit,
  346. .query_formats = query_formats,
  347. .inputs = displace_inputs,
  348. .outputs = displace_outputs,
  349. .priv_class = &displace_class,
  350. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL,
  351. };