Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6147 serge 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(©);
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
};