2 * Copyright (c) 2015 Paul B. Mahol
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/avassert.h"
22 #include "libavutil/eval.h"
23 #include "libavutil/imgutils.h"
24 #include "libavutil/mem.h"
25 #include "libavutil/opt.h"
32 typedef struct SwapRectContext
{
41 const AVPixFmtDescriptor
*desc
;
45 #define OFFSET(x) offsetof(SwapRectContext, x)
46 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
47 static const AVOption swaprect_options
[] = {
48 { "w", "set rect width", OFFSET(w
), AV_OPT_TYPE_STRING
, {.str
="w/2"}, 0, 0, .flags
= FLAGS
},
49 { "h", "set rect height", OFFSET(h
), AV_OPT_TYPE_STRING
, {.str
="h/2"}, 0, 0, .flags
= FLAGS
},
50 { "x1", "set 1st rect x top left coordinate", OFFSET(x1
), AV_OPT_TYPE_STRING
, {.str
="w/2"}, 0, 0, .flags
= FLAGS
},
51 { "y1", "set 1st rect y top left coordinate", OFFSET(y1
), AV_OPT_TYPE_STRING
, {.str
="h/2"}, 0, 0, .flags
= FLAGS
},
52 { "x2", "set 2nd rect x top left coordinate", OFFSET(x2
), AV_OPT_TYPE_STRING
, {.str
="0"}, 0, 0, .flags
= FLAGS
},
53 { "y2", "set 2nd rect y top left coordinate", OFFSET(y2
), AV_OPT_TYPE_STRING
, {.str
="0"}, 0, 0, .flags
= FLAGS
},
57 AVFILTER_DEFINE_CLASS(swaprect
);
59 static int query_formats(const AVFilterContext
*ctx
,
60 AVFilterFormatsConfig
**cfg_in
,
61 AVFilterFormatsConfig
**cfg_out
)
63 int reject_flags
= AV_PIX_FMT_FLAG_PAL
|
64 AV_PIX_FMT_FLAG_HWACCEL
|
65 AV_PIX_FMT_FLAG_BITSTREAM
;
67 return ff_set_common_formats2(ctx
, cfg_in
, cfg_out
,
68 ff_formats_pixdesc_filter(0, reject_flags
));
71 static const char *const var_names
[] = { "w", "h", "a", "n", "t",
76 enum { VAR_W
, VAR_H
, VAR_A
, VAR_N
, VAR_T
,
80 VAR_SAR
, VAR_DAR
, VAR_VARS_NB
};
82 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
84 FilterLink
*inl
= ff_filter_link(inlink
);
85 AVFilterContext
*ctx
= inlink
->dst
;
86 AVFilterLink
*outlink
= ctx
->outputs
[0];
87 SwapRectContext
*s
= ctx
->priv
;
88 double var_values
[VAR_VARS_NB
];
99 var_values
[VAR_W
] = inlink
->w
;
100 var_values
[VAR_H
] = inlink
->h
;
101 var_values
[VAR_A
] = (float) inlink
->w
/ inlink
->h
;
102 var_values
[VAR_SAR
] = inlink
->sample_aspect_ratio
.num
? av_q2d(inlink
->sample_aspect_ratio
) : 1;
103 var_values
[VAR_DAR
] = var_values
[VAR_A
] * var_values
[VAR_SAR
];
104 var_values
[VAR_N
] = inl
->frame_count_out
;
105 var_values
[VAR_T
] = in
->pts
== AV_NOPTS_VALUE
? NAN
: in
->pts
* av_q2d(inlink
->time_base
);
107 FF_DISABLE_DEPRECATION_WARNINGS
108 var_values
[VAR_POS
] = in
->pkt_pos
== -1 ? NAN
: in
->pkt_pos
;
109 FF_ENABLE_DEPRECATION_WARNINGS
112 ret
= av_expr_parse_and_eval(&dw
, s
->w
,
113 var_names
, &var_values
[0],
114 NULL
, NULL
, NULL
, NULL
,
119 ret
= av_expr_parse_and_eval(&dh
, s
->h
,
120 var_names
, &var_values
[0],
121 NULL
, NULL
, NULL
, NULL
,
126 ret
= av_expr_parse_and_eval(&dx1
, s
->x1
,
127 var_names
, &var_values
[0],
128 NULL
, NULL
, NULL
, NULL
,
133 ret
= av_expr_parse_and_eval(&dy1
, s
->y1
,
134 var_names
, &var_values
[0],
135 NULL
, NULL
, NULL
, NULL
,
140 ret
= av_expr_parse_and_eval(&dx2
, s
->x2
,
141 var_names
, &var_values
[0],
142 NULL
, NULL
, NULL
, NULL
,
147 ret
= av_expr_parse_and_eval(&dy2
, s
->y2
,
148 var_names
, &var_values
[0],
149 NULL
, NULL
, NULL
, NULL
,
154 w
= dw
; h
= dh
; x1
[0] = dx1
; y1
[0] = dy1
; x2
[0] = dx2
; y2
[0] = dy2
;
156 x1
[0] = av_clip(x1
[0], 0, inlink
->w
- 1);
157 y1
[0] = av_clip(y1
[0], 0, inlink
->h
- 1);
159 x2
[0] = av_clip(x2
[0], 0, inlink
->w
- 1);
160 y2
[0] = av_clip(y2
[0], 0, inlink
->h
- 1);
162 ah
[1] = ah
[2] = AV_CEIL_RSHIFT(h
, s
->desc
->log2_chroma_h
);
164 aw
[1] = aw
[2] = AV_CEIL_RSHIFT(w
, s
->desc
->log2_chroma_w
);
167 w
= FFMIN3(w
, inlink
->w
- x1
[0], inlink
->w
- x2
[0]);
168 h
= FFMIN3(h
, inlink
->h
- y1
[0], inlink
->h
- y2
[0]);
170 ph
[1] = ph
[2] = AV_CEIL_RSHIFT(h
, s
->desc
->log2_chroma_h
);
172 pw
[1] = pw
[2] = AV_CEIL_RSHIFT(w
, s
->desc
->log2_chroma_w
);
175 lh
[1] = lh
[2] = AV_CEIL_RSHIFT(inlink
->h
, s
->desc
->log2_chroma_h
);
176 lh
[0] = lh
[3] = inlink
->h
;
177 lw
[1] = lw
[2] = AV_CEIL_RSHIFT(inlink
->w
, s
->desc
->log2_chroma_w
);
178 lw
[0] = lw
[3] = inlink
->w
;
180 x1
[1] = x1
[2] = (x1
[0] >> s
->desc
->log2_chroma_w
);
181 x1
[0] = x1
[3] = x1
[0];
182 y1
[1] = y1
[2] = (y1
[0] >> s
->desc
->log2_chroma_h
);
183 y1
[0] = y1
[3] = y1
[0];
185 x2
[1] = x2
[2] = (x2
[0] >> s
->desc
->log2_chroma_w
);
186 x2
[0] = x2
[3] = x2
[0];
187 y2
[1] = y2
[2] = (y2
[0] >> s
->desc
->log2_chroma_h
);
188 y2
[0] = y2
[3] = y2
[0];
191 av_assert0(FFMAX(x1
[1], x2
[1]) + pw
[1] <= lw
[1]);
192 av_assert0(FFMAX(y1
[1], y2
[1]) + ph
[1] <= lh
[1]);
194 for (p
= 0; p
< s
->nb_planes
; p
++) {
195 if (ph
[p
] == ah
[p
] && pw
[p
] == aw
[p
]) {
196 uint8_t *src
= in
->data
[p
] + y1
[p
] * in
->linesize
[p
] + x1
[p
] * s
->pixsteps
[p
];
197 uint8_t *dst
= in
->data
[p
] + y2
[p
] * in
->linesize
[p
] + x2
[p
] * s
->pixsteps
[p
];
199 for (y
= 0; y
< ph
[p
]; y
++) {
200 memcpy(s
->temp
, src
, pw
[p
] * s
->pixsteps
[p
]);
201 memmove(src
, dst
, pw
[p
] * s
->pixsteps
[p
]);
202 memcpy(dst
, s
->temp
, pw
[p
] * s
->pixsteps
[p
]);
203 src
+= in
->linesize
[p
];
204 dst
+= in
->linesize
[p
];
209 return ff_filter_frame(outlink
, in
);
212 static int config_input(AVFilterLink
*inlink
)
214 AVFilterContext
*ctx
= inlink
->dst
;
215 SwapRectContext
*s
= ctx
->priv
;
217 if (!s
->w
|| !s
->h
||
220 return AVERROR(EINVAL
);
222 s
->desc
= av_pix_fmt_desc_get(inlink
->format
);
223 av_image_fill_max_pixsteps(s
->pixsteps
, NULL
, s
->desc
);
224 s
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
226 s
->temp
= av_malloc_array(inlink
->w
, s
->pixsteps
[0]);
228 return AVERROR(ENOMEM
);
233 static av_cold
void uninit(AVFilterContext
*ctx
)
235 SwapRectContext
*s
= ctx
->priv
;
239 static const AVFilterPad inputs
[] = {
242 .type
= AVMEDIA_TYPE_VIDEO
,
243 .flags
= AVFILTERPAD_FLAG_NEEDS_WRITABLE
,
244 .filter_frame
= filter_frame
,
245 .config_props
= config_input
,
249 const FFFilter ff_vf_swaprect
= {
250 .p
.name
= "swaprect",
251 .p
.description
= NULL_IF_CONFIG_SMALL("Swap 2 rectangular objects in video."),
252 .p
.priv_class
= &swaprect_class
,
253 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
,
254 .priv_size
= sizeof(SwapRectContext
),
256 FILTER_INPUTS(inputs
),
257 FILTER_OUTPUTS(ff_video_default_filterpad
),
258 FILTER_QUERY_FUNC2(query_formats
),
259 .process_command
= ff_filter_process_command
,