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.

449 lines
16KB

  1. /*
  2. * Copyright (c) 2012 Fredrik Mellbin
  3. * Copyright (c) 2013 Clément Bœsch
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "libavutil/opt.h"
  22. #include "libavutil/pixdesc.h"
  23. #include "libavutil/timestamp.h"
  24. #include "avfilter.h"
  25. #include "filters.h"
  26. #include "internal.h"
  27. #define INPUT_MAIN 0
  28. #define INPUT_CLEANSRC 1
  29. struct qitem {
  30. AVFrame *frame;
  31. int64_t maxbdiff;
  32. int64_t totdiff;
  33. };
  34. typedef struct DecimateContext {
  35. const AVClass *class;
  36. struct qitem *queue; ///< window of cycle frames and the associated data diff
  37. int fid; ///< current frame id in the queue
  38. int filled; ///< 1 if the queue is filled, 0 otherwise
  39. AVFrame *last; ///< last frame from the previous queue
  40. AVFrame **clean_src; ///< frame queue for the clean source
  41. int got_frame[2]; ///< frame request flag for each input stream
  42. AVRational ts_unit; ///< timestamp units for the output frames
  43. int64_t last_pts; ///< last output timestamp
  44. int64_t start_pts; ///< base for output timestamps
  45. uint32_t eof; ///< bitmask for end of stream
  46. int hsub, vsub; ///< chroma subsampling values
  47. int depth;
  48. int nxblocks, nyblocks;
  49. int bdiffsize;
  50. int64_t *bdiffs;
  51. /* options */
  52. int cycle;
  53. double dupthresh_flt;
  54. double scthresh_flt;
  55. int64_t dupthresh;
  56. int64_t scthresh;
  57. int blockx, blocky;
  58. int ppsrc;
  59. int chroma;
  60. } DecimateContext;
  61. #define OFFSET(x) offsetof(DecimateContext, x)
  62. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  63. static const AVOption decimate_options[] = {
  64. { "cycle", "set the number of frame from which one will be dropped", OFFSET(cycle), AV_OPT_TYPE_INT, {.i64 = 5}, 2, 25, FLAGS },
  65. { "dupthresh", "set duplicate threshold", OFFSET(dupthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl = 1.1}, 0, 100, FLAGS },
  66. { "scthresh", "set scene change threshold", OFFSET(scthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl = 15.0}, 0, 100, FLAGS },
  67. { "blockx", "set the size of the x-axis blocks used during metric calculations", OFFSET(blockx), AV_OPT_TYPE_INT, {.i64 = 32}, 4, 1<<9, FLAGS },
  68. { "blocky", "set the size of the y-axis blocks used during metric calculations", OFFSET(blocky), AV_OPT_TYPE_INT, {.i64 = 32}, 4, 1<<9, FLAGS },
  69. { "ppsrc", "mark main input as a pre-processed input and activate clean source input stream", OFFSET(ppsrc), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
  70. { "chroma", "set whether or not chroma is considered in the metric calculations", OFFSET(chroma), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
  71. { NULL }
  72. };
  73. AVFILTER_DEFINE_CLASS(decimate);
  74. static void calc_diffs(const DecimateContext *dm, struct qitem *q,
  75. const AVFrame *f1, const AVFrame *f2)
  76. {
  77. int64_t maxdiff = -1;
  78. int64_t *bdiffs = dm->bdiffs;
  79. int plane, i, j;
  80. memset(bdiffs, 0, dm->bdiffsize * sizeof(*bdiffs));
  81. for (plane = 0; plane < (dm->chroma && f1->data[2] ? 3 : 1); plane++) {
  82. int x, y, xl;
  83. const int linesize1 = f1->linesize[plane];
  84. const int linesize2 = f2->linesize[plane];
  85. const uint8_t *f1p = f1->data[plane];
  86. const uint8_t *f2p = f2->data[plane];
  87. int width = plane ? AV_CEIL_RSHIFT(f1->width, dm->hsub) : f1->width;
  88. int height = plane ? AV_CEIL_RSHIFT(f1->height, dm->vsub) : f1->height;
  89. int hblockx = dm->blockx / 2;
  90. int hblocky = dm->blocky / 2;
  91. if (plane) {
  92. hblockx >>= dm->hsub;
  93. hblocky >>= dm->vsub;
  94. }
  95. for (y = 0; y < height; y++) {
  96. int ydest = y / hblocky;
  97. int xdest = 0;
  98. #define CALC_DIFF(nbits) do { \
  99. for (x = 0; x < width; x += hblockx) { \
  100. int64_t acc = 0; \
  101. int m = FFMIN(width, x + hblockx); \
  102. for (xl = x; xl < m; xl++) \
  103. acc += abs(((const uint##nbits##_t *)f1p)[xl] - \
  104. ((const uint##nbits##_t *)f2p)[xl]); \
  105. bdiffs[ydest * dm->nxblocks + xdest] += acc; \
  106. xdest++; \
  107. } \
  108. } while (0)
  109. if (dm->depth == 8) CALC_DIFF(8);
  110. else CALC_DIFF(16);
  111. f1p += linesize1;
  112. f2p += linesize2;
  113. }
  114. }
  115. for (i = 0; i < dm->nyblocks - 1; i++) {
  116. for (j = 0; j < dm->nxblocks - 1; j++) {
  117. int64_t tmp = bdiffs[ i * dm->nxblocks + j ]
  118. + bdiffs[ i * dm->nxblocks + j + 1]
  119. + bdiffs[(i + 1) * dm->nxblocks + j ]
  120. + bdiffs[(i + 1) * dm->nxblocks + j + 1];
  121. if (tmp > maxdiff)
  122. maxdiff = tmp;
  123. }
  124. }
  125. q->totdiff = 0;
  126. for (i = 0; i < dm->bdiffsize; i++)
  127. q->totdiff += bdiffs[i];
  128. q->maxbdiff = maxdiff;
  129. }
  130. static int filter_frame(AVFilterLink *inlink, AVFrame *in)
  131. {
  132. int scpos = -1, duppos = -1;
  133. int drop = INT_MIN, i, lowest = 0, ret;
  134. AVFilterContext *ctx = inlink->dst;
  135. AVFilterLink *outlink = ctx->outputs[0];
  136. DecimateContext *dm = ctx->priv;
  137. AVFrame *prv;
  138. /* update frames queue(s) */
  139. if (FF_INLINK_IDX(inlink) == INPUT_MAIN) {
  140. dm->queue[dm->fid].frame = in;
  141. dm->got_frame[INPUT_MAIN] = 1;
  142. } else {
  143. dm->clean_src[dm->fid] = in;
  144. dm->got_frame[INPUT_CLEANSRC] = 1;
  145. }
  146. if (!dm->got_frame[INPUT_MAIN] || (dm->ppsrc && !dm->got_frame[INPUT_CLEANSRC]))
  147. return 0;
  148. dm->got_frame[INPUT_MAIN] = dm->got_frame[INPUT_CLEANSRC] = 0;
  149. if (dm->ppsrc)
  150. in = dm->queue[dm->fid].frame;
  151. if (in) {
  152. /* update frame metrics */
  153. prv = dm->fid ? dm->queue[dm->fid - 1].frame : dm->last;
  154. if (!prv) {
  155. dm->queue[dm->fid].maxbdiff = INT64_MAX;
  156. dm->queue[dm->fid].totdiff = INT64_MAX;
  157. } else {
  158. calc_diffs(dm, &dm->queue[dm->fid], prv, in);
  159. }
  160. if (++dm->fid != dm->cycle)
  161. return 0;
  162. av_frame_free(&dm->last);
  163. dm->last = av_frame_clone(in);
  164. dm->fid = 0;
  165. /* we have a complete cycle, select the frame to drop */
  166. lowest = 0;
  167. for (i = 0; i < dm->cycle; i++) {
  168. if (dm->queue[i].totdiff > dm->scthresh)
  169. scpos = i;
  170. if (dm->queue[i].maxbdiff < dm->queue[lowest].maxbdiff)
  171. lowest = i;
  172. }
  173. if (dm->queue[lowest].maxbdiff < dm->dupthresh)
  174. duppos = lowest;
  175. drop = scpos >= 0 && duppos < 0 ? scpos : lowest;
  176. }
  177. /* metrics debug */
  178. if (av_log_get_level() >= AV_LOG_DEBUG) {
  179. av_log(ctx, AV_LOG_DEBUG, "1/%d frame drop:\n", dm->cycle);
  180. for (i = 0; i < dm->cycle && dm->queue[i].frame; i++) {
  181. av_log(ctx, AV_LOG_DEBUG," #%d: totdiff=%08"PRIx64" maxbdiff=%08"PRIx64"%s%s%s%s\n",
  182. i + 1, dm->queue[i].totdiff, dm->queue[i].maxbdiff,
  183. i == scpos ? " sc" : "",
  184. i == duppos ? " dup" : "",
  185. i == lowest ? " lowest" : "",
  186. i == drop ? " [DROP]" : "");
  187. }
  188. }
  189. /* push all frames except the drop */
  190. ret = 0;
  191. for (i = 0; i < dm->cycle && dm->queue[i].frame; i++) {
  192. if (i == drop) {
  193. if (dm->ppsrc)
  194. av_frame_free(&dm->clean_src[i]);
  195. av_frame_free(&dm->queue[i].frame);
  196. } else {
  197. AVFrame *frame = dm->queue[i].frame;
  198. dm->queue[i].frame = NULL;
  199. if (frame->pts != AV_NOPTS_VALUE && dm->start_pts == AV_NOPTS_VALUE)
  200. dm->start_pts = frame->pts;
  201. if (dm->ppsrc) {
  202. av_frame_free(&frame);
  203. frame = dm->clean_src[i];
  204. if (!frame)
  205. continue;
  206. dm->clean_src[i] = NULL;
  207. }
  208. frame->pts = av_rescale_q(outlink->frame_count_in, dm->ts_unit, (AVRational){1,1}) +
  209. (dm->start_pts == AV_NOPTS_VALUE ? 0 : dm->start_pts);
  210. dm->last_pts = frame->pts;
  211. ret = ff_filter_frame(outlink, frame);
  212. if (ret < 0)
  213. break;
  214. }
  215. }
  216. return ret;
  217. }
  218. static int activate(AVFilterContext *ctx)
  219. {
  220. DecimateContext *dm = ctx->priv;
  221. AVFrame *frame = NULL;
  222. int ret = 0, status;
  223. int64_t pts;
  224. FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
  225. if ((dm->got_frame[INPUT_MAIN] == 0) && !(dm->eof & (1 << INPUT_MAIN)) &&
  226. (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_MAIN], &frame)) > 0) {
  227. ret = filter_frame(ctx->inputs[INPUT_MAIN], frame);
  228. if (ret < 0)
  229. return ret;
  230. }
  231. if (ret < 0)
  232. return ret;
  233. if (dm->ppsrc &&
  234. (dm->got_frame[INPUT_CLEANSRC] == 0) && !(dm->eof & (1 << INPUT_CLEANSRC)) &&
  235. (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_CLEANSRC], &frame)) > 0) {
  236. ret = filter_frame(ctx->inputs[INPUT_CLEANSRC], frame);
  237. if (ret < 0)
  238. return ret;
  239. }
  240. if (ret < 0) {
  241. return ret;
  242. } else if (dm->eof == ((1 << INPUT_MAIN) | (dm->ppsrc << INPUT_CLEANSRC))) {
  243. ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, dm->last_pts);
  244. return 0;
  245. } else if (!(dm->eof & (1 << INPUT_MAIN)) && ff_inlink_acknowledge_status(ctx->inputs[INPUT_MAIN], &status, &pts)) {
  246. if (status == AVERROR_EOF) { // flushing
  247. dm->eof |= 1 << INPUT_MAIN;
  248. if (dm->ppsrc)
  249. filter_frame(ctx->inputs[INPUT_CLEANSRC], NULL);
  250. filter_frame(ctx->inputs[INPUT_MAIN], NULL);
  251. ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, dm->last_pts);
  252. return 0;
  253. }
  254. } else if (dm->ppsrc && !(dm->eof & (1 << INPUT_CLEANSRC)) && ff_inlink_acknowledge_status(ctx->inputs[INPUT_CLEANSRC], &status, &pts)) {
  255. if (status == AVERROR_EOF) { // flushing
  256. dm->eof |= 1 << INPUT_CLEANSRC;
  257. filter_frame(ctx->inputs[INPUT_MAIN], NULL);
  258. filter_frame(ctx->inputs[INPUT_CLEANSRC], NULL);
  259. ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, dm->last_pts);
  260. return 0;
  261. }
  262. }
  263. if (ff_inlink_queued_frames(ctx->inputs[INPUT_MAIN]) > 0 &&
  264. (dm->ppsrc && ff_inlink_queued_frames(ctx->inputs[INPUT_CLEANSRC]) > 0)) {
  265. ff_filter_set_ready(ctx, 100);
  266. } else if (ff_outlink_frame_wanted(ctx->outputs[0])) {
  267. if (dm->got_frame[INPUT_MAIN] == 0)
  268. ff_inlink_request_frame(ctx->inputs[INPUT_MAIN]);
  269. if (dm->ppsrc && (dm->got_frame[INPUT_CLEANSRC] == 0))
  270. ff_inlink_request_frame(ctx->inputs[INPUT_CLEANSRC]);
  271. }
  272. return 0;
  273. }
  274. static av_cold int decimate_init(AVFilterContext *ctx)
  275. {
  276. DecimateContext *dm = ctx->priv;
  277. AVFilterPad pad = {
  278. .name = "main",
  279. .type = AVMEDIA_TYPE_VIDEO,
  280. };
  281. int ret;
  282. if ((ret = ff_insert_inpad(ctx, INPUT_MAIN, &pad)) < 0)
  283. return ret;
  284. if (dm->ppsrc) {
  285. pad.name = "clean_src";
  286. pad.config_props = NULL;
  287. if ((ret = ff_insert_inpad(ctx, INPUT_CLEANSRC, &pad)) < 0)
  288. return ret;
  289. }
  290. if ((dm->blockx & (dm->blockx - 1)) ||
  291. (dm->blocky & (dm->blocky - 1))) {
  292. av_log(ctx, AV_LOG_ERROR, "blockx and blocky settings must be power of two\n");
  293. return AVERROR(EINVAL);
  294. }
  295. dm->start_pts = AV_NOPTS_VALUE;
  296. return 0;
  297. }
  298. static av_cold void decimate_uninit(AVFilterContext *ctx)
  299. {
  300. int i;
  301. DecimateContext *dm = ctx->priv;
  302. av_frame_free(&dm->last);
  303. av_freep(&dm->bdiffs);
  304. if (dm->queue) {
  305. for (i = 0; i < dm->cycle; i++)
  306. av_frame_free(&dm->queue[i].frame);
  307. }
  308. av_freep(&dm->queue);
  309. if (dm->clean_src) {
  310. for (i = 0; i < dm->cycle; i++)
  311. av_frame_free(&dm->clean_src[i]);
  312. }
  313. av_freep(&dm->clean_src);
  314. }
  315. static int query_formats(AVFilterContext *ctx)
  316. {
  317. static const enum AVPixelFormat pix_fmts[] = {
  318. #define PF_NOALPHA(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf
  319. #define PF_ALPHA(suf) AV_PIX_FMT_YUVA420##suf, AV_PIX_FMT_YUVA422##suf, AV_PIX_FMT_YUVA444##suf
  320. #define PF(suf) PF_NOALPHA(suf), PF_ALPHA(suf)
  321. PF(P), PF(P9), PF(P10), PF_NOALPHA(P12), PF_NOALPHA(P14), PF(P16),
  322. AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV440P12,
  323. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
  324. AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
  325. AV_PIX_FMT_YUVJ411P,
  326. AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14,
  327. AV_PIX_FMT_GRAY16,
  328. AV_PIX_FMT_NONE
  329. };
  330. AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
  331. if (!fmts_list)
  332. return AVERROR(ENOMEM);
  333. return ff_set_common_formats(ctx, fmts_list);
  334. }
  335. static int config_output(AVFilterLink *outlink)
  336. {
  337. AVFilterContext *ctx = outlink->src;
  338. DecimateContext *dm = ctx->priv;
  339. const AVFilterLink *inlink = ctx->inputs[INPUT_MAIN];
  340. AVRational fps = inlink->frame_rate;
  341. int max_value;
  342. const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format);
  343. const int w = inlink->w;
  344. const int h = inlink->h;
  345. dm->hsub = pix_desc->log2_chroma_w;
  346. dm->vsub = pix_desc->log2_chroma_h;
  347. dm->depth = pix_desc->comp[0].depth;
  348. max_value = (1 << dm->depth) - 1;
  349. dm->scthresh = (int64_t)(((int64_t)max_value * w * h * dm->scthresh_flt) / 100);
  350. dm->dupthresh = (int64_t)(((int64_t)max_value * dm->blockx * dm->blocky * dm->dupthresh_flt) / 100);
  351. dm->nxblocks = (w + dm->blockx/2 - 1) / (dm->blockx/2);
  352. dm->nyblocks = (h + dm->blocky/2 - 1) / (dm->blocky/2);
  353. dm->bdiffsize = dm->nxblocks * dm->nyblocks;
  354. dm->bdiffs = av_malloc_array(dm->bdiffsize, sizeof(*dm->bdiffs));
  355. dm->queue = av_calloc(dm->cycle, sizeof(*dm->queue));
  356. if (!dm->bdiffs || !dm->queue)
  357. return AVERROR(ENOMEM);
  358. if (dm->ppsrc) {
  359. dm->clean_src = av_calloc(dm->cycle, sizeof(*dm->clean_src));
  360. if (!dm->clean_src)
  361. return AVERROR(ENOMEM);
  362. }
  363. if (!fps.num || !fps.den) {
  364. av_log(ctx, AV_LOG_ERROR, "The input needs a constant frame rate; "
  365. "current rate of %d/%d is invalid\n", fps.num, fps.den);
  366. return AVERROR(EINVAL);
  367. }
  368. fps = av_mul_q(fps, (AVRational){dm->cycle - 1, dm->cycle});
  369. av_log(ctx, AV_LOG_VERBOSE, "FPS: %d/%d -> %d/%d\n",
  370. inlink->frame_rate.num, inlink->frame_rate.den, fps.num, fps.den);
  371. outlink->time_base = inlink->time_base;
  372. outlink->frame_rate = fps;
  373. outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
  374. if (dm->ppsrc) {
  375. outlink->w = ctx->inputs[INPUT_CLEANSRC]->w;
  376. outlink->h = ctx->inputs[INPUT_CLEANSRC]->h;
  377. } else {
  378. outlink->w = inlink->w;
  379. outlink->h = inlink->h;
  380. }
  381. dm->ts_unit = av_inv_q(av_mul_q(fps, outlink->time_base));
  382. return 0;
  383. }
  384. static const AVFilterPad decimate_outputs[] = {
  385. {
  386. .name = "default",
  387. .type = AVMEDIA_TYPE_VIDEO,
  388. .config_props = config_output,
  389. },
  390. { NULL }
  391. };
  392. AVFilter ff_vf_decimate = {
  393. .name = "decimate",
  394. .description = NULL_IF_CONFIG_SMALL("Decimate frames (post field matching filter)."),
  395. .init = decimate_init,
  396. .activate = activate,
  397. .uninit = decimate_uninit,
  398. .priv_size = sizeof(DecimateContext),
  399. .query_formats = query_formats,
  400. .outputs = decimate_outputs,
  401. .priv_class = &decimate_class,
  402. .flags = AVFILTER_FLAG_DYNAMIC_INPUTS,
  403. };