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.

191 lines
5.5KB

  1. /*
  2. * Copyright (c) 2011 Michael Niedermayer
  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. * The vsrc_color filter from Stefano Sabatini was used as template to create
  21. * this
  22. */
  23. /**
  24. * @file
  25. * Mandelbrot fraktal renderer
  26. */
  27. #include "avfilter.h"
  28. #include "libavutil/imgutils.h"
  29. #include "libavutil/parseutils.h"
  30. enum Outer{
  31. ITERATION_COUNT,
  32. NORMALIZED_ITERATION_COUNT,
  33. };
  34. typedef struct {
  35. int w, h;
  36. AVRational time_base;
  37. uint64_t pts;
  38. int maxiter;
  39. double start_x;
  40. double start_y;
  41. double start_scale;
  42. double end_scale;
  43. double end_pts;
  44. double bailout;
  45. enum Outer outer;
  46. } MBContext;
  47. static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
  48. {
  49. MBContext *mb = ctx->priv;
  50. char frame_size [128] = "320x240";
  51. char frame_rate [128] = "25";
  52. AVRational frame_rate_q;
  53. int ret;
  54. mb->maxiter=256;
  55. mb->start_x=0;
  56. mb->start_y=1;
  57. mb->start_scale=3.0;
  58. mb->end_scale=0.3;
  59. mb->end_pts=200;
  60. mb->bailout=100;
  61. mb->outer= NORMALIZED_ITERATION_COUNT;
  62. if (args)
  63. sscanf(args, "%127[^:]:%127[^:]:%d,%lf:%lf:%lf", frame_size, frame_rate, &mb->maxiter, &mb->start_x, &mb->start_y, &mb->start_scale);
  64. if (av_parse_video_size(&mb->w, &mb->h, frame_size) < 0) {
  65. av_log(ctx, AV_LOG_ERROR, "Invalid frame size: %s\n", frame_size);
  66. return AVERROR(EINVAL);
  67. }
  68. mb->start_scale /=mb->h;
  69. mb->end_scale /=mb->h;
  70. if (av_parse_video_rate(&frame_rate_q, frame_rate) < 0 ||
  71. frame_rate_q.den <= 0 || frame_rate_q.num <= 0) {
  72. av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: %s\n", frame_rate);
  73. return AVERROR(EINVAL);
  74. }
  75. mb->time_base.num = frame_rate_q.den;
  76. mb->time_base.den = frame_rate_q.num;
  77. return 0;
  78. }
  79. static av_cold void uninit(AVFilterContext *ctx)
  80. {
  81. MBContext *mb = ctx->priv;
  82. int i;
  83. }
  84. static int query_formats(AVFilterContext *ctx)
  85. {
  86. static const enum PixelFormat pix_fmts[] = {
  87. PIX_FMT_BGR32,
  88. PIX_FMT_NONE
  89. };
  90. avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
  91. return 0;
  92. }
  93. static int config_props(AVFilterLink *inlink)
  94. {
  95. AVFilterContext *ctx = inlink->src;
  96. MBContext *mb = ctx->priv;
  97. if (av_image_check_size(mb->w, mb->h, 0, ctx) < 0)
  98. return AVERROR(EINVAL);
  99. inlink->w = mb->w;
  100. inlink->h = mb->h;
  101. inlink->time_base = mb->time_base;
  102. return 0;
  103. }
  104. static void draw_mandelbrot(AVFilterContext *ctx, uint32_t *color, int linesize, int64_t pts)
  105. {
  106. MBContext *mb = ctx->priv;
  107. int x,y,i;
  108. double scale= mb->start_scale*pow(mb->end_scale/mb->start_scale, pts/mb->end_pts);
  109. for(y=0; y<mb->h; y++){
  110. for(x=0; x<mb->w; x++){
  111. const double cr=mb->start_x+scale*(x-mb->w/2);
  112. const double ci=mb->start_y+scale*(y-mb->h/2);
  113. double zr=cr;
  114. double zi=ci;
  115. uint32_t c=0;
  116. for(i=0; i<mb->maxiter; i++){
  117. double t;
  118. if(zr*zr + zi*zi > mb->bailout){
  119. switch(mb->outer){
  120. case ITERATION_COUNT: zr= i; break;
  121. case NORMALIZED_ITERATION_COUNT: zr= i + (log(log(mb->bailout)) - log(log(sqrt(zr*zr + zi*zi))))/log(2); break;
  122. }
  123. c= lrintf((sin(zr)+1)*127) + lrintf((sin(zr/1.234)+1)*127)*256*256 + lrintf((sin(zr/100)+1)*127)*256;
  124. break;
  125. }
  126. t= zr*zr - zi*zi;
  127. zi= 2*zr*zi + ci;
  128. zr= t + cr;
  129. }
  130. color[x + y*linesize]= c;
  131. }
  132. }
  133. }
  134. static int request_frame(AVFilterLink *link)
  135. {
  136. MBContext *mb = link->src->priv;
  137. AVFilterBufferRef *picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, mb->w, mb->h);
  138. picref->video->sample_aspect_ratio = (AVRational) {1, 1};
  139. picref->pts = mb->pts++;
  140. picref->pos = -1;
  141. avfilter_start_frame(link, avfilter_ref_buffer(picref, ~0));
  142. draw_mandelbrot(link->src, picref->data[0], picref->linesize[0]/4, picref->pts);
  143. avfilter_draw_slice(link, 0, mb->h, 1);
  144. avfilter_end_frame(link);
  145. avfilter_unref_buffer(picref);
  146. return 0;
  147. }
  148. AVFilter avfilter_vsrc_mandelbrot = {
  149. .name = "mandelbrot",
  150. .description = NULL_IF_CONFIG_SMALL("Mandelbrot renderer"),
  151. .priv_size = sizeof(MBContext),
  152. .init = init,
  153. .uninit = uninit,
  154. .query_formats = query_formats,
  155. .inputs = (const AVFilterPad[]) {{ .name = NULL}},
  156. .outputs = (const AVFilterPad[]) {{ .name = "default",
  157. .type = AVMEDIA_TYPE_VIDEO,
  158. .request_frame = request_frame,
  159. .config_props = config_props },
  160. { .name = NULL}},
  161. };