Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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