]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_vflip.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / vf_vflip.c
1 /*
2  * Copyright (c) 2007 Bobby Bingham
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 /**
22  * @file
23  * video vertical flip filter
24  */
25
26 #include "libavutil/internal.h"
27 #include "libavutil/opt.h"
28 #include "libavutil/pixdesc.h"
29 #include "avfilter.h"
30 #include "internal.h"
31 #include "video.h"
32
33 typedef struct FlipContext {
34     const AVClass *class;
35     int vsub;   ///< vertical chroma subsampling
36     int bayer;
37 } FlipContext;
38
39 static const AVOption vflip_options[] = {
40     { NULL }
41 };
42
43 AVFILTER_DEFINE_CLASS(vflip);
44
45 static int config_input(AVFilterLink *link)
46 {
47     FlipContext *flip = link->dst->priv;
48     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
49
50     flip->vsub = desc->log2_chroma_h;
51     flip->bayer = !!(desc->flags & AV_PIX_FMT_FLAG_BAYER);
52
53     return 0;
54 }
55
56 static AVFrame *get_video_buffer(AVFilterLink *link, int w, int h)
57 {
58     FlipContext *flip = link->dst->priv;
59     AVFrame *frame;
60     int i;
61
62     frame = ff_get_video_buffer(link->dst->outputs[0], w, h);
63     if (!frame)
64         return NULL;
65
66     for (i = 0; i < 4; i ++) {
67         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
68         int height = AV_CEIL_RSHIFT(h, vsub);
69
70         if (frame->data[i]) {
71             frame->data[i] += (height - 1) * frame->linesize[i];
72             frame->linesize[i] = -frame->linesize[i];
73         }
74     }
75
76     return frame;
77 }
78
79 static int flip_bayer(AVFilterLink *link, AVFrame *in)
80 {
81     AVFilterContext *ctx  = link->dst;
82     AVFilterLink *outlink = ctx->outputs[0];
83     AVFrame *out;
84     uint8_t *inrow = in->data[0], *outrow;
85     int i, width = outlink->w << (av_pix_fmt_desc_get(link->format)->comp[0].step > 1);
86     if (outlink->h & 1) {
87         av_log(ctx, AV_LOG_ERROR, "Bayer vertical flip needs even height\n");
88         return AVERROR_INVALIDDATA;
89     }
90
91     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
92     if (!out) {
93         av_frame_free(&in);
94         return AVERROR(ENOMEM);
95     }
96     av_frame_copy_props(out, in);
97     outrow = out->data[0] + out->linesize[0] * (outlink->h - 2);
98     for (i = 0; i < outlink->h >> 1; i++) {
99         memcpy(outrow, inrow, width);
100         memcpy(outrow + out->linesize[0], inrow + in->linesize[0], width);
101         inrow  += 2 *  in->linesize[0];
102         outrow -= 2 * out->linesize[0];
103     }
104     av_frame_free(&in);
105     return ff_filter_frame(outlink, out);
106 }
107
108 static int filter_frame(AVFilterLink *link, AVFrame *frame)
109 {
110     FlipContext *flip = link->dst->priv;
111     int i;
112
113     if (flip->bayer)
114         return flip_bayer(link, frame);
115
116     for (i = 0; i < 4; i ++) {
117         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
118         int height = AV_CEIL_RSHIFT(link->h, vsub);
119
120         if (frame->data[i]) {
121             frame->data[i] += (height - 1) * frame->linesize[i];
122             frame->linesize[i] = -frame->linesize[i];
123         }
124     }
125
126     return ff_filter_frame(link->dst->outputs[0], frame);
127 }
128 static const AVFilterPad avfilter_vf_vflip_inputs[] = {
129     {
130         .name             = "default",
131         .type             = AVMEDIA_TYPE_VIDEO,
132         .get_video_buffer = get_video_buffer,
133         .filter_frame     = filter_frame,
134         .config_props     = config_input,
135     },
136     { NULL }
137 };
138
139 static const AVFilterPad avfilter_vf_vflip_outputs[] = {
140     {
141         .name = "default",
142         .type = AVMEDIA_TYPE_VIDEO,
143     },
144     { NULL }
145 };
146
147 const AVFilter ff_vf_vflip = {
148     .name        = "vflip",
149     .description = NULL_IF_CONFIG_SMALL("Flip the input video vertically."),
150     .priv_size   = sizeof(FlipContext),
151     .priv_class  = &vflip_class,
152     .inputs      = avfilter_vf_vflip_inputs,
153     .outputs     = avfilter_vf_vflip_outputs,
154     .flags       = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
155 };