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.

199 lines
6.1KB

  1. /*
  2. * Copyright (c) 2020 Nicolas George
  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/opt.h"
  22. #include "libavutil/pixdesc.h"
  23. #include "avfilter.h"
  24. #include "formats.h"
  25. #include "filters.h"
  26. typedef struct UntileContext {
  27. const AVClass *class;
  28. unsigned w, h;
  29. unsigned current;
  30. unsigned nb_frames;
  31. AVFrame *frame;
  32. const AVPixFmtDescriptor *desc;
  33. int64_t dpts, pts;
  34. int max_step[4];
  35. } UntileContext;
  36. #define OFFSET(x) offsetof(UntileContext, x)
  37. #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  38. static const AVOption untile_options[] = {
  39. { "layout", "set grid size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE,
  40. {.str = "6x5"}, 0, 0, FLAGS },
  41. { NULL }
  42. };
  43. AVFILTER_DEFINE_CLASS(untile);
  44. static av_cold int init(AVFilterContext *ctx)
  45. {
  46. UntileContext *s = ctx->priv;
  47. if (s->w > UINT_MAX / s->h) {
  48. av_log(ctx, AV_LOG_ERROR, "Tile size %ux%u is insane.\n",
  49. s->w, s->h);
  50. return AVERROR(EINVAL);
  51. }
  52. s->nb_frames = s->w * s->h;
  53. return 0;
  54. }
  55. static int query_formats(AVFilterContext *ctx)
  56. {
  57. AVFilterFormats *formats = NULL;
  58. int ret;
  59. ret = ff_formats_pixdesc_filter(&formats, 0,
  60. AV_PIX_FMT_FLAG_HWACCEL |
  61. AV_PIX_FMT_FLAG_BITSTREAM |
  62. FF_PIX_FMT_FLAG_SW_FLAT_SUB);
  63. if (ret < 0)
  64. return ret;
  65. return ff_set_common_formats(ctx, formats);
  66. }
  67. static int config_output(AVFilterLink *outlink)
  68. {
  69. AVFilterContext *ctx = outlink->src;
  70. UntileContext *s = ctx->priv;
  71. AVFilterLink *inlink = ctx->inputs[0];
  72. AVRational dt;
  73. s->desc = av_pix_fmt_desc_get(outlink->format);
  74. if (inlink->w % (s->w << s->desc->log2_chroma_w) ||
  75. inlink->h % (s->h << s->desc->log2_chroma_h)) {
  76. av_log(ctx, AV_LOG_ERROR,
  77. "Input resolution %ux%u not multiple of layout %ux%u.\n",
  78. inlink->w, inlink->h, s->w, s->h);
  79. return AVERROR(EINVAL);
  80. }
  81. outlink->w = inlink->w / s->w;
  82. outlink->h = inlink->h / s->h;
  83. outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
  84. outlink->frame_rate = av_mul_q(inlink->frame_rate, av_make_q(s->nb_frames, 1));
  85. if (outlink->frame_rate.num)
  86. dt = av_inv_q(outlink->frame_rate);
  87. else
  88. dt = av_mul_q(inlink->time_base, av_make_q(1, s->nb_frames));
  89. outlink->time_base = av_gcd_q(inlink->time_base, dt, AV_TIME_BASE / 2, AV_TIME_BASE_Q);
  90. s->dpts = av_rescale_q(1, dt, outlink->time_base);
  91. av_log(ctx, AV_LOG_VERBOSE, "frame interval: %"PRId64"*%d/%d\n",
  92. s->dpts, dt.num, dt.den);
  93. av_image_fill_max_pixsteps(s->max_step, NULL, s->desc);
  94. return 0;
  95. }
  96. static int activate(AVFilterContext *ctx)
  97. {
  98. UntileContext *s = ctx->priv;
  99. AVFilterLink *inlink = ctx->inputs[0];
  100. AVFilterLink *outlink = ctx->outputs[0];
  101. AVFrame *out;
  102. int i, x, y, ret;
  103. FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
  104. if (!s->frame) {
  105. ret = ff_inlink_consume_frame(inlink, &s->frame);
  106. if (ret < 0)
  107. return ret;
  108. if (ret)
  109. s->pts = av_rescale_q(s->frame->pts, inlink->time_base, outlink->time_base);
  110. }
  111. if (s->frame) {
  112. if (s->current == s->nb_frames - 1) {
  113. out = s->frame;
  114. s->frame = NULL;
  115. } else {
  116. out = av_frame_clone(s->frame);
  117. if (!out)
  118. return AVERROR(ENOMEM);
  119. }
  120. x = outlink->w * (s->current % s->w);
  121. y = outlink->h * (s->current / s->w);
  122. out->width = outlink->w;
  123. out->height = outlink->h;
  124. out->data[0] += y * out->linesize[0];
  125. out->data[0] += x * s->max_step[0];
  126. if (!(s->desc->flags & AV_PIX_FMT_FLAG_PAL || s->desc->flags & FF_PSEUDOPAL)) {
  127. for (i = 1; i < 3; i ++) {
  128. if (out->data[i]) {
  129. out->data[i] += (y >> s->desc->log2_chroma_w) * out->linesize[i];
  130. out->data[i] += (x >> s->desc->log2_chroma_h) * s->max_step[i];
  131. }
  132. }
  133. }
  134. if (out->data[3]) {
  135. out->data[3] += y * out->linesize[3];
  136. out->data[3] += x * s->max_step[3];
  137. }
  138. out->pts = s->pts;
  139. s->pts += s->dpts;
  140. if (++s->current == s->nb_frames)
  141. s->current = 0;
  142. return ff_filter_frame(outlink, out);
  143. }
  144. FF_FILTER_FORWARD_STATUS(inlink, outlink);
  145. FF_FILTER_FORWARD_WANTED(outlink, inlink);
  146. return FFERROR_NOT_READY;
  147. }
  148. static av_cold void uninit(AVFilterContext *ctx)
  149. {
  150. UntileContext *s = ctx->priv;
  151. av_frame_free(&s->frame);
  152. }
  153. static const AVFilterPad untile_inputs[] = {
  154. {
  155. .name = "default",
  156. .type = AVMEDIA_TYPE_VIDEO,
  157. },
  158. { NULL }
  159. };
  160. static const AVFilterPad untile_outputs[] = {
  161. {
  162. .name = "default",
  163. .type = AVMEDIA_TYPE_VIDEO,
  164. .config_props = config_output,
  165. },
  166. { NULL }
  167. };
  168. AVFilter ff_vf_untile = {
  169. .name = "untile",
  170. .description = NULL_IF_CONFIG_SMALL("Untile a frame into a sequence of frames."),
  171. .init = init,
  172. .uninit = uninit,
  173. .query_formats = query_formats,
  174. .activate = activate,
  175. .priv_size = sizeof(UntileContext),
  176. .inputs = untile_inputs,
  177. .outputs = untile_outputs,
  178. .priv_class = &untile_class,
  179. };