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.

183 lines
5.5KB

  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. PermsContext *perms = ctx->priv;
  50. // TODO: add a seed option
  51. if (perms->mode == MODE_RANDOM)
  52. av_lfg_init(&perms->lfg, av_get_random_seed());
  53. return 0;
  54. }
  55. enum perm { RO, RW };
  56. static const char *perm_str[2] = { "RO", "RW" };
  57. static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
  58. {
  59. int ret;
  60. AVFilterContext *ctx = inlink->dst;
  61. PermsContext *perms = ctx->priv;
  62. AVFrame *out = frame;
  63. enum perm in_perm = av_frame_is_writable(frame) ? RW : RO;
  64. enum perm out_perm;
  65. switch (perms->mode) {
  66. case MODE_TOGGLE: out_perm = in_perm == RO ? RW : RO; break;
  67. case MODE_RANDOM: out_perm = av_lfg_get(&perms->lfg) & 1 ? RW : RO; break;
  68. case MODE_RO: out_perm = RO; break;
  69. case MODE_RW: out_perm = RW; break;
  70. default: out_perm = in_perm; break;
  71. }
  72. av_log(ctx, AV_LOG_VERBOSE, "%s -> %s%s\n",
  73. perm_str[in_perm], perm_str[out_perm],
  74. in_perm == out_perm ? " (no-op)" : "");
  75. if (in_perm == RO && out_perm == RW) {
  76. if ((ret = av_frame_make_writable(frame)) < 0)
  77. return ret;
  78. } else if (in_perm == RW && out_perm == RO) {
  79. out = av_frame_clone(frame);
  80. if (!out)
  81. return AVERROR(ENOMEM);
  82. }
  83. ret = ff_filter_frame(ctx->outputs[0], out);
  84. if (in_perm == RW && out_perm == RO)
  85. av_frame_free(&frame);
  86. return ret;
  87. }
  88. static const char *const shorthand[] = { "mode", NULL };
  89. #if CONFIG_APERMS_FILTER
  90. #define aperms_options options
  91. AVFILTER_DEFINE_CLASS(aperms);
  92. static av_cold int aperms_init(AVFilterContext *ctx, const char *args)
  93. {
  94. return init(ctx, args, &aperms_class);
  95. }
  96. static const AVFilterPad aperms_inputs[] = {
  97. {
  98. .name = "default",
  99. .type = AVMEDIA_TYPE_AUDIO,
  100. .filter_frame = filter_frame,
  101. },
  102. { NULL }
  103. };
  104. static const AVFilterPad aperms_outputs[] = {
  105. {
  106. .name = "default",
  107. .type = AVMEDIA_TYPE_AUDIO,
  108. },
  109. { NULL }
  110. };
  111. AVFilter avfilter_af_aperms = {
  112. .name = "aperms",
  113. .description = NULL_IF_CONFIG_SMALL("Set permissions for the output audio frame."),
  114. .init = aperms_init,
  115. .priv_size = sizeof(PermsContext),
  116. .inputs = aperms_inputs,
  117. .outputs = aperms_outputs,
  118. .priv_class = &aperms_class,
  119. .shorthand = shorthand,
  120. };
  121. #endif /* CONFIG_APERMS_FILTER */
  122. #if CONFIG_PERMS_FILTER
  123. #define perms_options options
  124. AVFILTER_DEFINE_CLASS(perms);
  125. static av_cold int perms_init(AVFilterContext *ctx, const char *args)
  126. {
  127. return init(ctx, args, &perms_class);
  128. }
  129. static const AVFilterPad perms_inputs[] = {
  130. {
  131. .name = "default",
  132. .type = AVMEDIA_TYPE_VIDEO,
  133. .filter_frame = filter_frame,
  134. },
  135. { NULL }
  136. };
  137. static const AVFilterPad perms_outputs[] = {
  138. {
  139. .name = "default",
  140. .type = AVMEDIA_TYPE_VIDEO,
  141. },
  142. { NULL }
  143. };
  144. AVFilter avfilter_vf_perms = {
  145. .name = "perms",
  146. .description = NULL_IF_CONFIG_SMALL("Set permissions for the output video frame."),
  147. .init = perms_init,
  148. .priv_size = sizeof(PermsContext),
  149. .inputs = perms_inputs,
  150. .outputs = perms_outputs,
  151. .priv_class = &perms_class,
  152. .shorthand = shorthand,
  153. };
  154. #endif /* CONFIG_PERMS_FILTER */