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.

472 lines
13KB

  1. /*
  2. * Copyright (c) 2016 The FFmpeg Project
  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/channel_layout.h"
  21. #include "libavutil/opt.h"
  22. #include "avfilter.h"
  23. #include "audio.h"
  24. #include "formats.h"
  25. typedef struct CrystalizerContext {
  26. const AVClass *class;
  27. float mult;
  28. int clip;
  29. AVFrame *prev;
  30. int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
  31. } CrystalizerContext;
  32. #define OFFSET(x) offsetof(CrystalizerContext, x)
  33. #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
  34. static const AVOption crystalizer_options[] = {
  35. { "i", "set intensity", OFFSET(mult), AV_OPT_TYPE_FLOAT, {.dbl=2.0},-10, 10, A },
  36. { "c", "enable clipping", OFFSET(clip), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, A },
  37. { NULL }
  38. };
  39. AVFILTER_DEFINE_CLASS(crystalizer);
  40. static int query_formats(AVFilterContext *ctx)
  41. {
  42. AVFilterFormats *formats = NULL;
  43. AVFilterChannelLayouts *layouts = NULL;
  44. static const enum AVSampleFormat sample_fmts[] = {
  45. AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP,
  46. AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP,
  47. AV_SAMPLE_FMT_NONE
  48. };
  49. int ret;
  50. formats = ff_make_format_list(sample_fmts);
  51. if (!formats)
  52. return AVERROR(ENOMEM);
  53. ret = ff_set_common_formats(ctx, formats);
  54. if (ret < 0)
  55. return ret;
  56. layouts = ff_all_channel_counts();
  57. if (!layouts)
  58. return AVERROR(ENOMEM);
  59. ret = ff_set_common_channel_layouts(ctx, layouts);
  60. if (ret < 0)
  61. return ret;
  62. formats = ff_all_samplerates();
  63. return ff_set_common_samplerates(ctx, formats);
  64. }
  65. typedef struct ThreadData {
  66. void **d;
  67. void **p;
  68. const void **s;
  69. int nb_samples;
  70. int channels;
  71. float mult;
  72. int clip;
  73. } ThreadData;
  74. static int filter_flt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  75. {
  76. ThreadData *td = arg;
  77. void **d = td->d;
  78. void **p = td->p;
  79. const void **s = td->s;
  80. const int nb_samples = td->nb_samples;
  81. const int channels = td->channels;
  82. const float mult = td->mult;
  83. const int clip = td->clip;
  84. const int start = (channels * jobnr) / nb_jobs;
  85. const int end = (channels * (jobnr+1)) / nb_jobs;
  86. float *prv = p[0];
  87. int n, c;
  88. for (c = start; c < end; c++) {
  89. const float *src = s[0];
  90. float *dst = d[0];
  91. for (n = 0; n < nb_samples; n++) {
  92. float current = src[c];
  93. dst[c] = current + (current - prv[c]) * mult;
  94. prv[c] = current;
  95. if (clip) {
  96. dst[c] = av_clipf(dst[c], -1, 1);
  97. }
  98. dst += channels;
  99. src += channels;
  100. }
  101. }
  102. return 0;
  103. }
  104. static int filter_dbl(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  105. {
  106. ThreadData *td = arg;
  107. void **d = td->d;
  108. void **p = td->p;
  109. const void **s = td->s;
  110. const int nb_samples = td->nb_samples;
  111. const int channels = td->channels;
  112. double mult = td->mult;
  113. const int clip = td->clip;
  114. const int start = (channels * jobnr) / nb_jobs;
  115. const int end = (channels * (jobnr+1)) / nb_jobs;
  116. double *prv = p[0];
  117. int n, c;
  118. for (c = start; c < end; c++) {
  119. const double *src = s[0];
  120. double *dst = d[0];
  121. for (n = 0; n < nb_samples; n++) {
  122. double current = src[c];
  123. dst[c] = current + (current - prv[c]) * mult;
  124. prv[c] = current;
  125. if (clip) {
  126. dst[c] = av_clipd(dst[c], -1, 1);
  127. }
  128. dst += channels;
  129. src += channels;
  130. }
  131. }
  132. return 0;
  133. }
  134. static int filter_fltp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  135. {
  136. ThreadData *td = arg;
  137. void **d = td->d;
  138. void **p = td->p;
  139. const void **s = td->s;
  140. const int nb_samples = td->nb_samples;
  141. const int channels = td->channels;
  142. float mult = td->mult;
  143. const int clip = td->clip;
  144. const int start = (channels * jobnr) / nb_jobs;
  145. const int end = (channels * (jobnr+1)) / nb_jobs;
  146. int n, c;
  147. for (c = start; c < end; c++) {
  148. const float *src = s[c];
  149. float *dst = d[c];
  150. float *prv = p[c];
  151. for (n = 0; n < nb_samples; n++) {
  152. float current = src[n];
  153. dst[n] = current + (current - prv[0]) * mult;
  154. prv[0] = current;
  155. if (clip) {
  156. dst[n] = av_clipf(dst[n], -1, 1);
  157. }
  158. }
  159. }
  160. return 0;
  161. }
  162. static int filter_dblp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  163. {
  164. ThreadData *td = arg;
  165. void **d = td->d;
  166. void **p = td->p;
  167. const void **s = td->s;
  168. const int nb_samples = td->nb_samples;
  169. const int channels = td->channels;
  170. const double mult = td->mult;
  171. const int clip = td->clip;
  172. const int start = (channels * jobnr) / nb_jobs;
  173. const int end = (channels * (jobnr+1)) / nb_jobs;
  174. int n, c;
  175. for (c = start; c < end; c++) {
  176. const double *src = s[c];
  177. double *dst = d[c];
  178. double *prv = p[c];
  179. for (n = 0; n < nb_samples; n++) {
  180. double current = src[n];
  181. dst[n] = current + (current - prv[0]) * mult;
  182. prv[0] = current;
  183. if (clip) {
  184. dst[n] = av_clipd(dst[n], -1, 1);
  185. }
  186. }
  187. }
  188. return 0;
  189. }
  190. static int ifilter_flt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  191. {
  192. ThreadData *td = arg;
  193. void **d = td->d;
  194. void **p = td->p;
  195. const void **s = td->s;
  196. const int nb_samples = td->nb_samples;
  197. const int channels = td->channels;
  198. const float mult = -td->mult;
  199. const float div = -td->mult + 1.f;
  200. const int clip = td->clip;
  201. const int start = (channels * jobnr) / nb_jobs;
  202. const int end = (channels * (jobnr+1)) / nb_jobs;
  203. float *prv = p[0];
  204. int n, c;
  205. for (c = start; c < end; c++) {
  206. const float *src = s[0];
  207. float *dst = d[0];
  208. for (n = 0; n < nb_samples; n++) {
  209. float current = src[c];
  210. dst[c] = (current + prv[c] * mult) / div;
  211. prv[c] = dst[c];
  212. if (clip) {
  213. dst[c] = av_clipf(dst[c], -1, 1);
  214. }
  215. dst += channels;
  216. src += channels;
  217. }
  218. }
  219. return 0;
  220. }
  221. static int ifilter_dbl(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  222. {
  223. ThreadData *td = arg;
  224. void **d = td->d;
  225. void **p = td->p;
  226. const void **s = td->s;
  227. const int nb_samples = td->nb_samples;
  228. const int channels = td->channels;
  229. const double mult = -td->mult;
  230. const double div = -td->mult + 1.f;
  231. const int clip = td->clip;
  232. const int start = (channels * jobnr) / nb_jobs;
  233. const int end = (channels * (jobnr+1)) / nb_jobs;
  234. double *prv = p[0];
  235. int n, c;
  236. for (c = start; c < end; c++) {
  237. const double *src = s[0];
  238. double *dst = d[0];
  239. for (n = 0; n < nb_samples; n++) {
  240. double current = src[c];
  241. dst[c] = (current + prv[c] * mult) / div;
  242. prv[c] = dst[c];
  243. if (clip) {
  244. dst[c] = av_clipd(dst[c], -1, 1);
  245. }
  246. dst += channels;
  247. src += channels;
  248. }
  249. }
  250. return 0;
  251. }
  252. static int ifilter_fltp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  253. {
  254. ThreadData *td = arg;
  255. void **d = td->d;
  256. void **p = td->p;
  257. const void **s = td->s;
  258. const int nb_samples = td->nb_samples;
  259. const int channels = td->channels;
  260. const float mult = -td->mult;
  261. const float div = -td->mult + 1.f;
  262. const int clip = td->clip;
  263. const int start = (channels * jobnr) / nb_jobs;
  264. const int end = (channels * (jobnr+1)) / nb_jobs;
  265. int n, c;
  266. for (c = start; c < end; c++) {
  267. const float *src = s[c];
  268. float *dst = d[c];
  269. float *prv = p[c];
  270. for (n = 0; n < nb_samples; n++) {
  271. float current = src[n];
  272. dst[n] = (current + prv[0] * mult) / div;
  273. prv[0] = dst[n];
  274. if (clip) {
  275. dst[n] = av_clipf(dst[n], -1, 1);
  276. }
  277. }
  278. }
  279. return 0;
  280. }
  281. static int ifilter_dblp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
  282. {
  283. ThreadData *td = arg;
  284. void **d = td->d;
  285. void **p = td->p;
  286. const void **s = td->s;
  287. const int nb_samples = td->nb_samples;
  288. const int channels = td->channels;
  289. const double mult = -td->mult;
  290. const double div = -td->mult + 1.f;
  291. const int clip = td->clip;
  292. const int start = (channels * jobnr) / nb_jobs;
  293. const int end = (channels * (jobnr+1)) / nb_jobs;
  294. int n, c;
  295. for (c = start; c < end; c++) {
  296. const double *src = s[c];
  297. double *dst = d[c];
  298. double *prv = p[c];
  299. for (n = 0; n < nb_samples; n++) {
  300. double current = src[n];
  301. dst[n] = (current + prv[0] * mult) / div;
  302. prv[0] = dst[n];
  303. if (clip) {
  304. dst[n] = av_clipd(dst[n], -1, 1);
  305. }
  306. }
  307. }
  308. return 0;
  309. }
  310. static int config_input(AVFilterLink *inlink)
  311. {
  312. AVFilterContext *ctx = inlink->dst;
  313. CrystalizerContext *s = ctx->priv;
  314. switch (inlink->format) {
  315. case AV_SAMPLE_FMT_FLT: s->filter = s->mult >= 0.f ? filter_flt : ifilter_flt; break;
  316. case AV_SAMPLE_FMT_DBL: s->filter = s->mult >= 0.f ? filter_dbl : ifilter_dbl; break;
  317. case AV_SAMPLE_FMT_FLTP: s->filter = s->mult >= 0.f ? filter_fltp : ifilter_fltp; break;
  318. case AV_SAMPLE_FMT_DBLP: s->filter = s->mult >= 0.f ? filter_dblp : ifilter_dblp; break;
  319. }
  320. return 0;
  321. }
  322. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  323. {
  324. AVFilterContext *ctx = inlink->dst;
  325. AVFilterLink *outlink = ctx->outputs[0];
  326. CrystalizerContext *s = ctx->priv;
  327. AVFrame *out;
  328. ThreadData td;
  329. if (!s->prev) {
  330. s->prev = ff_get_audio_buffer(inlink, 1);
  331. if (!s->prev) {
  332. av_frame_free(&in);
  333. return AVERROR(ENOMEM);
  334. }
  335. }
  336. if (av_frame_is_writable(in)) {
  337. out = in;
  338. } else {
  339. out = ff_get_audio_buffer(outlink, in->nb_samples);
  340. if (!out) {
  341. av_frame_free(&in);
  342. return AVERROR(ENOMEM);
  343. }
  344. av_frame_copy_props(out, in);
  345. }
  346. td.d = (void **)out->extended_data;
  347. td.s = (const void **)in->extended_data;
  348. td.p = (void **)s->prev->extended_data;
  349. td.nb_samples = in->nb_samples;
  350. td.channels = in->channels;
  351. td.mult = ctx->is_disabled ? 0.f : s->mult;
  352. td.clip = s->clip;
  353. ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN(inlink->channels,
  354. ff_filter_get_nb_threads(ctx)));
  355. if (out != in)
  356. av_frame_free(&in);
  357. return ff_filter_frame(outlink, out);
  358. }
  359. static av_cold void uninit(AVFilterContext *ctx)
  360. {
  361. CrystalizerContext *s = ctx->priv;
  362. av_frame_free(&s->prev);
  363. }
  364. static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
  365. char *res, int res_len, int flags)
  366. {
  367. int ret;
  368. ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
  369. if (ret < 0)
  370. return ret;
  371. return config_input(ctx->inputs[0]);
  372. }
  373. static const AVFilterPad inputs[] = {
  374. {
  375. .name = "default",
  376. .type = AVMEDIA_TYPE_AUDIO,
  377. .filter_frame = filter_frame,
  378. .config_props = config_input,
  379. },
  380. { NULL }
  381. };
  382. static const AVFilterPad outputs[] = {
  383. {
  384. .name = "default",
  385. .type = AVMEDIA_TYPE_AUDIO,
  386. },
  387. { NULL }
  388. };
  389. AVFilter ff_af_crystalizer = {
  390. .name = "crystalizer",
  391. .description = NULL_IF_CONFIG_SMALL("Simple audio noise sharpening filter."),
  392. .query_formats = query_formats,
  393. .priv_size = sizeof(CrystalizerContext),
  394. .priv_class = &crystalizer_class,
  395. .uninit = uninit,
  396. .inputs = inputs,
  397. .outputs = outputs,
  398. .process_command = process_command,
  399. .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
  400. AVFILTER_FLAG_SLICE_THREADS,
  401. };