vf_shuffleplanes.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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/avstring.h"
  19. #include "libavutil/common.h"
  20. #include "libavutil/internal.h"
  21. #include "libavutil/opt.h"
  22. #include "libavutil/pixdesc.h"
  23. #include "libavutil/pixfmt.h"
  24. #include "avfilter.h"
  25. #include "internal.h"
  26. #include "video.h"
  27. typedef struct ShufflePlanesContext {
  28. const AVClass *class;
  29. /* number of planes in the selected pixel format */
  30. int planes;
  31. /* mapping indices */
  32. int map[4];
  33. /* set to 1 if some plane is used more than once, so we need to make a copy */
  34. int copy;
  35. } ShufflePlanesContext;
  36. static av_cold int shuffleplanes_config_input(AVFilterLink *inlink)
  37. {
  38. AVFilterContext *ctx = inlink->dst;
  39. ShufflePlanesContext *s = ctx->priv;
  40. const AVPixFmtDescriptor *desc;
  41. int used[4] = { 0 };
  42. int i;
  43. s->copy = 0;
  44. s->planes = av_pix_fmt_count_planes(inlink->format);
  45. desc = av_pix_fmt_desc_get(inlink->format);
  46. for (i = 0; i < s->planes; i++) {
  47. if (s->map[i] >= s->planes) {
  48. av_log(ctx, AV_LOG_ERROR,
  49. "Non-existing input plane #%d mapped to output plane #%d.\n",
  50. s->map[i], i);
  51. return AVERROR(EINVAL);
  52. }
  53. if ((desc->log2_chroma_h || desc->log2_chroma_w) &&
  54. (i == 1 || i == 2) != (s->map[i] == 1 || s->map[i] == 2)) {
  55. av_log(ctx, AV_LOG_ERROR,
  56. "Cannot map between a subsampled chroma plane and a luma "
  57. "or alpha plane.\n");
  58. return AVERROR(EINVAL);
  59. }
  60. if ((desc->flags & AV_PIX_FMT_FLAG_PAL ||
  61. desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) &&
  62. (i == 1) != (s->map[i] == 1)) {
  63. av_log(ctx, AV_LOG_ERROR,
  64. "Cannot map between a palette plane and a data plane.\n");
  65. return AVERROR(EINVAL);
  66. }
  67. if (used[s->map[i]])
  68. s->copy = 1;
  69. used[s->map[i]]++;
  70. }
  71. return 0;
  72. }
  73. static int shuffleplanes_filter_frame(AVFilterLink *inlink, AVFrame *frame)
  74. {
  75. AVFilterContext *ctx = inlink->dst;
  76. ShufflePlanesContext *s = ctx->priv;
  77. uint8_t *shuffled_data[4] = { NULL };
  78. int shuffled_linesize[4] = { 0 };
  79. int i, ret;
  80. for (i = 0; i < s->planes; i++) {
  81. shuffled_data[i] = frame->data[s->map[i]];
  82. shuffled_linesize[i] = frame->linesize[s->map[i]];
  83. }
  84. memcpy(frame->data, shuffled_data, sizeof(shuffled_data));
  85. memcpy(frame->linesize, shuffled_linesize, sizeof(shuffled_linesize));
  86. if (s->copy) {
  87. AVFrame *copy = ff_get_video_buffer(ctx->outputs[0], frame->width, frame->height);
  88. if (!copy) {
  89. ret = AVERROR(ENOMEM);
  90. goto fail;
  91. }
  92. av_frame_copy(copy, frame);
  93. ret = av_frame_copy_props(copy, frame);
  94. if (ret < 0) {
  95. av_frame_free(&copy);
  96. goto fail;
  97. }
  98. av_frame_free(&frame);
  99. frame = copy;
  100. }
  101. return ff_filter_frame(ctx->outputs[0], frame);
  102. fail:
  103. av_frame_free(&frame);
  104. return ret;
  105. }
  106. #define OFFSET(x) offsetof(ShufflePlanesContext, x)
  107. #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM)
  108. static const AVOption shuffleplanes_options[] = {
  109. { "map0", "Index of the input plane to be used as the first output plane ", OFFSET(map[0]), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, FLAGS },
  110. { "map1", "Index of the input plane to be used as the second output plane ", OFFSET(map[1]), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 4, FLAGS },
  111. { "map2", "Index of the input plane to be used as the third output plane ", OFFSET(map[2]), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, FLAGS },
  112. { "map3", "Index of the input plane to be used as the fourth output plane ", OFFSET(map[3]), AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 4, FLAGS },
  113. { NULL },
  114. };
  115. static const AVClass shuffleplanes_class = {
  116. .class_name = "shuffleplanes",
  117. .item_name = av_default_item_name,
  118. .option = shuffleplanes_options,
  119. .version = LIBAVUTIL_VERSION_INT,
  120. };
  121. static const AVFilterPad shuffleplanes_inputs[] = {
  122. {
  123. .name = "default",
  124. .type = AVMEDIA_TYPE_VIDEO,
  125. .config_props = shuffleplanes_config_input,
  126. .filter_frame = shuffleplanes_filter_frame,
  127. .get_video_buffer = ff_null_get_video_buffer,
  128. },
  129. { NULL },
  130. };
  131. static const AVFilterPad shuffleplanes_outputs[] = {
  132. {
  133. .name = "default",
  134. .type = AVMEDIA_TYPE_VIDEO,
  135. },
  136. { NULL },
  137. };
  138. AVFilter ff_vf_shuffleplanes = {
  139. .name = "shuffleplanes",
  140. .description = NULL_IF_CONFIG_SMALL("Shuffle video planes"),
  141. .priv_size = sizeof(ShufflePlanesContext),
  142. .priv_class = &shuffleplanes_class,
  143. .inputs = shuffleplanes_inputs,
  144. .outputs = shuffleplanes_outputs,
  145. };