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.

300 lines
10KB

  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "libavutil/opt.h"
  19. #include "libavutil/imgutils.h"
  20. #include "avfilter.h"
  21. #include "formats.h"
  22. #include "internal.h"
  23. #include "video.h"
  24. typedef struct CASContext {
  25. const AVClass *class;
  26. float strength;
  27. int planes;
  28. int nb_planes;
  29. int depth;
  30. int planeheight[4];
  31. int planewidth[4];
  32. AVFrame *in;
  33. int (*do_slice)(AVFilterContext *s, void *arg,
  34. int jobnr, int nb_jobs);
  35. } CASContext;
  36. static inline float lerpf(float v0, float v1, float f)
  37. {
  38. return v0 + (v1 - v0) * f;
  39. }
  40. static int cas_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
  41. {
  42. CASContext *s = avctx->priv;
  43. const float strength = -lerpf(16.f, 4.01f, s->strength);
  44. AVFrame *out = arg;
  45. AVFrame *in = s->in;
  46. for (int p = 0; p < s->nb_planes; p++) {
  47. const int slice_start = (s->planeheight[p] * jobnr) / nb_jobs;
  48. const int slice_end = (s->planeheight[p] * (jobnr+1)) / nb_jobs;
  49. const int linesize = out->linesize[p];
  50. const int in_linesize = in->linesize[p];
  51. const int w = s->planewidth[p];
  52. const int w1 = w - 1;
  53. const int h = s->planeheight[p];
  54. const int h1 = h - 1;
  55. uint8_t *dst = out->data[p] + slice_start * linesize;
  56. const uint8_t *src = in->data[p];
  57. if (!((1 << p) & s->planes)) {
  58. av_image_copy_plane(dst, linesize, src + slice_start * linesize, in_linesize,
  59. w, slice_end - slice_start);
  60. continue;
  61. }
  62. for (int y = slice_start; y < slice_end; y++) {
  63. const int y0 = FFMAX(y - 1, 0);
  64. const int y1 = FFMIN(y + 1, h1);
  65. for (int x = 0; x < w; x++) {
  66. const int x0 = FFMAX(x - 1, 0);
  67. const int x1 = FFMIN(x + 1, w1);
  68. int a = src[y0 * in_linesize + x0];
  69. int b = src[y0 * in_linesize + x];
  70. int c = src[y0 * in_linesize + x1];
  71. int d = src[y * in_linesize + x0];
  72. int e = src[y * in_linesize + x];
  73. int f = src[y * in_linesize + x1];
  74. int g = src[y1 * in_linesize + x0];
  75. int h = src[y1 * in_linesize + x];
  76. int i = src[y1 * in_linesize + x1];
  77. int mn, mn2, mx, mx2;
  78. float amp, weight;
  79. mn = FFMIN3(FFMIN3( d, e, f), b, h);
  80. mn2 = FFMIN3(FFMIN3(mn, a, c), g, i);
  81. mn = mn + mn2;
  82. mx = FFMAX3(FFMAX3( d, e, f), b, h);
  83. mx2 = FFMAX3(FFMAX3(mx, a, c), g, i);
  84. mx = mx + mx2;
  85. amp = sqrtf(av_clipf(FFMIN(mn, 511 - mx) / (float)mx, 0.f, 1.f));
  86. weight = amp / strength;
  87. dst[x] = av_clip_uint8(((b + d + f + h) * weight + e) / (1.f + 4.f * weight));
  88. }
  89. dst += linesize;
  90. }
  91. }
  92. return 0;
  93. }
  94. static int cas_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs)
  95. {
  96. CASContext *s = avctx->priv;
  97. const float strength = -lerpf(16.f, 4.01f, s->strength);
  98. const int max = 2 * (1 << s->depth) - 1;
  99. AVFrame *out = arg;
  100. AVFrame *in = s->in;
  101. for (int p = 0; p < s->nb_planes; p++) {
  102. const int slice_start = (s->planeheight[p] * jobnr) / nb_jobs;
  103. const int slice_end = (s->planeheight[p] * (jobnr+1)) / nb_jobs;
  104. const int linesize = out->linesize[p] / 2;
  105. const int in_linesize = in->linesize[p] / 2;
  106. const int w = s->planewidth[p];
  107. const int w1 = w - 1;
  108. const int h = s->planeheight[p];
  109. const int h1 = h - 1;
  110. uint16_t *dst = (uint16_t *)out->data[p] + slice_start * linesize;
  111. const uint16_t *src = (const uint16_t *)in->data[p];
  112. if (!((1 << p) & s->planes)) {
  113. av_image_copy_plane((uint8_t *)dst, linesize, (uint8_t *)(src + slice_start * linesize),
  114. in_linesize, w * 2, slice_end - slice_start);
  115. continue;
  116. }
  117. for (int y = slice_start; y < slice_end; y++) {
  118. const int y0 = FFMAX(y - 1, 0);
  119. const int y1 = FFMIN(y + 1, h1);
  120. for (int x = 0; x < w; x++) {
  121. const int x0 = FFMAX(x - 1, 0);
  122. const int x1 = FFMIN(x + 1, w1);
  123. int a = src[y0 * in_linesize + x0];
  124. int b = src[y0 * in_linesize + x];
  125. int c = src[y0 * in_linesize + x1];
  126. int d = src[y * in_linesize + x0];
  127. int e = src[y * in_linesize + x];
  128. int f = src[y * in_linesize + x1];
  129. int g = src[y1 * in_linesize + x0];
  130. int h = src[y1 * in_linesize + x];
  131. int i = src[y1 * in_linesize + x1];
  132. int mn, mn2, mx, mx2;
  133. float amp, weight;
  134. mn = FFMIN3(FFMIN3( d, e, f), b, h);
  135. mn2 = FFMIN3(FFMIN3(mn, a, c), g, i);
  136. mn = mn + mn2;
  137. mx = FFMAX3(FFMAX3( d, e, f), b, h);
  138. mx2 = FFMAX3(FFMAX3(mx, a, c), g, i);
  139. mx = mx + mx2;
  140. amp = sqrtf(av_clipf(FFMIN(mn, max - mx) / (float)mx, 0.f, 1.f));
  141. weight = amp / strength;
  142. dst[x] = av_clip_uintp2_c(((b + d + f + h) * weight + e) / (1.f + 4.f * weight), s->depth);
  143. }
  144. dst += linesize;
  145. }
  146. }
  147. return 0;
  148. }
  149. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  150. {
  151. AVFilterContext *ctx = inlink->dst;
  152. AVFilterLink *outlink = ctx->outputs[0];
  153. CASContext *s = ctx->priv;
  154. AVFrame *out;
  155. out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  156. if (!out) {
  157. av_frame_free(&in);
  158. return AVERROR(ENOMEM);
  159. }
  160. av_frame_copy_props(out, in);
  161. s->in = in;
  162. ctx->internal->execute(ctx, s->do_slice, out, NULL,
  163. FFMIN(in->height, ff_filter_get_nb_threads(ctx)));
  164. av_frame_free(&in);
  165. s->in = NULL;
  166. return ff_filter_frame(ctx->outputs[0], out);
  167. }
  168. static av_cold int query_formats(AVFilterContext *avctx)
  169. {
  170. static const enum AVPixelFormat pixel_fmts[] = {
  171. AV_PIX_FMT_GRAY8,
  172. AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10,
  173. AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
  174. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
  175. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
  176. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
  177. AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
  178. AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
  179. AV_PIX_FMT_YUVJ411P,
  180. AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
  181. AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
  182. AV_PIX_FMT_YUV440P10,
  183. AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
  184. AV_PIX_FMT_YUV440P12,
  185. AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
  186. AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
  187. AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
  188. AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
  189. AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
  190. AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
  191. AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
  192. AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
  193. AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
  194. AV_PIX_FMT_NONE
  195. };
  196. AVFilterFormats *formats = NULL;
  197. formats = ff_make_format_list(pixel_fmts);
  198. if (!formats)
  199. return AVERROR(ENOMEM);
  200. return ff_set_common_formats(avctx, formats);
  201. }
  202. static av_cold int config_input(AVFilterLink *inlink)
  203. {
  204. AVFilterContext *avctx = inlink->dst;
  205. CASContext *s = avctx->priv;
  206. const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
  207. s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
  208. s->planeheight[0] = s->planeheight[3] = inlink->h;
  209. s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
  210. s->planewidth[0] = s->planewidth[3] = inlink->w;
  211. s->depth = desc->comp[0].depth;
  212. s->nb_planes = desc->nb_components;
  213. s->do_slice = s->depth <= 8 ? cas_slice8 : cas_slice16;
  214. return 0;
  215. }
  216. static const AVFilterPad cas_inputs[] = {
  217. {
  218. .name = "default",
  219. .type = AVMEDIA_TYPE_VIDEO,
  220. .filter_frame = filter_frame,
  221. .config_props = config_input,
  222. },
  223. { NULL }
  224. };
  225. static const AVFilterPad cas_outputs[] = {
  226. {
  227. .name = "default",
  228. .type = AVMEDIA_TYPE_VIDEO,
  229. },
  230. { NULL }
  231. };
  232. #define OFFSET(x) offsetof(CASContext, x)
  233. #define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
  234. static const AVOption cas_options[] = {
  235. { "strength", "set the sharpening strength", OFFSET(strength), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, VF },
  236. { "planes", "set what planes to filter", OFFSET(planes), AV_OPT_TYPE_FLAGS, {.i64=7}, 0, 15, VF },
  237. { NULL }
  238. };
  239. AVFILTER_DEFINE_CLASS(cas);
  240. AVFilter ff_vf_cas = {
  241. .name = "cas",
  242. .description = NULL_IF_CONFIG_SMALL("Contrast Adaptive Sharpen."),
  243. .priv_size = sizeof(CASContext),
  244. .priv_class = &cas_class,
  245. .query_formats = query_formats,
  246. .inputs = cas_inputs,
  247. .outputs = cas_outputs,
  248. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
  249. .process_command = ff_filter_process_command,
  250. };