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.

184 lines
5.3KB

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