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.

188 lines
5.6KB

  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "libavutil/lfg.h"
  19. #include "libavutil/opt.h"
  20. #include "libavutil/random_seed.h"
  21. #include "audio.h"
  22. #include "video.h"
  23. enum mode {
  24. MODE_NONE,
  25. MODE_RO,
  26. MODE_RW,
  27. MODE_TOGGLE,
  28. MODE_RANDOM,
  29. NB_MODES
  30. };
  31. typedef struct {
  32. const AVClass *class;
  33. AVLFG lfg;
  34. enum mode mode;
  35. } PermsContext;
  36. #define OFFSET(x) offsetof(PermsContext, x)
  37. #define FLAGS AV_OPT_FLAG_FILTERING_PARAM
  38. static const AVOption options[] = {
  39. { "mode", "select permissions mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_NONE}, MODE_NONE, NB_MODES-1, FLAGS, "mode" },
  40. { "none", "do nothing", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_NONE}, INT_MIN, INT_MAX, FLAGS, "mode" },
  41. { "ro", "set all output frames read-only", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RO}, INT_MIN, INT_MAX, FLAGS, "mode" },
  42. { "rw", "set all output frames writable", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RW}, INT_MIN, INT_MAX, FLAGS, "mode" },
  43. { "toggle", "switch permissions", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TOGGLE}, INT_MIN, INT_MAX, FLAGS, "mode" },
  44. { "random", "set permissions randomly", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_RANDOM}, INT_MIN, INT_MAX, FLAGS, "mode" },
  45. { NULL }
  46. };
  47. static av_cold int init(AVFilterContext *ctx, const char *args, const AVClass *class)
  48. {
  49. int ret;
  50. PermsContext *perms = ctx->priv;
  51. static const char *shorthand[] = { "mode", NULL };
  52. perms->class = class;
  53. av_opt_set_defaults(perms);
  54. if ((ret = av_opt_set_from_string(perms, args, shorthand, "=", ":")) < 0)
  55. return ret;
  56. // TODO: add a seed option
  57. if (perms->mode == MODE_RANDOM)
  58. av_lfg_init(&perms->lfg, av_get_random_seed());
  59. av_opt_free(perms);
  60. return 0;
  61. }
  62. enum perm { RO, RW };
  63. static const char *perm_str[2] = { "RO", "RW" };
  64. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  65. {
  66. int ret;
  67. AVFilterContext *ctx = inlink->dst;
  68. PermsContext *perms = ctx->priv;
  69. AVFrame *out = frame;
  70. enum perm in_perm = av_frame_is_writable(frame) ? RW : RO;
  71. enum perm out_perm;
  72. switch (perms->mode) {
  73. case MODE_TOGGLE: out_perm = in_perm == RO ? RW : RO; break;
  74. case MODE_RANDOM: out_perm = av_lfg_get(&perms->lfg) & 1 ? RW : RO; break;
  75. case MODE_RO: out_perm = RO; break;
  76. case MODE_RW: out_perm = RW; break;
  77. default: out_perm = in_perm; break;
  78. }
  79. av_log(ctx, AV_LOG_VERBOSE, "%s -> %s%s\n",
  80. perm_str[in_perm], perm_str[out_perm],
  81. in_perm == out_perm ? " (no-op)" : "");
  82. if (in_perm == RO && out_perm == RW) {
  83. if ((ret = av_frame_make_writable(frame)) < 0)
  84. return ret;
  85. } else if (in_perm == RW && out_perm == RO) {
  86. out = av_frame_clone(frame);
  87. if (!out)
  88. return AVERROR(ENOMEM);
  89. }
  90. ret = ff_filter_frame(ctx->outputs[0], out);
  91. if (in_perm == RW && out_perm == RO)
  92. av_frame_free(&frame);
  93. return ret;
  94. }
  95. #if CONFIG_APERMS_FILTER
  96. #define aperms_options options
  97. AVFILTER_DEFINE_CLASS(aperms);
  98. static av_cold int aperms_init(AVFilterContext *ctx, const char *args)
  99. {
  100. return init(ctx, args, &aperms_class);
  101. }
  102. static const AVFilterPad aperms_inputs[] = {
  103. {
  104. .name = "default",
  105. .type = AVMEDIA_TYPE_AUDIO,
  106. .filter_frame = filter_frame,
  107. },
  108. { NULL }
  109. };
  110. static const AVFilterPad aperms_outputs[] = {
  111. {
  112. .name = "default",
  113. .type = AVMEDIA_TYPE_AUDIO,
  114. },
  115. { NULL }
  116. };
  117. AVFilter avfilter_af_aperms = {
  118. .name = "aperms",
  119. .description = NULL_IF_CONFIG_SMALL("Set permissions for the output audio frame."),
  120. .init = aperms_init,
  121. .priv_size = sizeof(PermsContext),
  122. .inputs = aperms_inputs,
  123. .outputs = aperms_outputs,
  124. .priv_class = &aperms_class,
  125. };
  126. #endif /* CONFIG_APERMS_FILTER */
  127. #if CONFIG_PERMS_FILTER
  128. #define perms_options options
  129. AVFILTER_DEFINE_CLASS(perms);
  130. static av_cold int perms_init(AVFilterContext *ctx, const char *args)
  131. {
  132. return init(ctx, args, &perms_class);
  133. }
  134. static const AVFilterPad perms_inputs[] = {
  135. {
  136. .name = "default",
  137. .type = AVMEDIA_TYPE_VIDEO,
  138. .filter_frame = filter_frame,
  139. },
  140. { NULL }
  141. };
  142. static const AVFilterPad perms_outputs[] = {
  143. {
  144. .name = "default",
  145. .type = AVMEDIA_TYPE_VIDEO,
  146. },
  147. { NULL }
  148. };
  149. AVFilter avfilter_vf_perms = {
  150. .name = "perms",
  151. .description = NULL_IF_CONFIG_SMALL("Set permissions for the output video frame."),
  152. .init = perms_init,
  153. .priv_size = sizeof(PermsContext),
  154. .inputs = perms_inputs,
  155. .outputs = perms_outputs,
  156. .priv_class = &perms_class,
  157. };
  158. #endif /* CONFIG_PERMS_FILTER */