2 * Copyright (c) 2010 Brandon Mintern
3 * Copyright (c) 2007 Bobby Bingham
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 * based heavily on vf_negate.c by Bobby Bingham
28 #include "libavutil/common.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/pixdesc.h"
39 typedef struct FadeContext
{
42 int factor
, fade_per_frame
;
43 int start_frame
, nb_frames
;
44 unsigned int frame_index
, stop_frame
;
48 static av_cold
int init(AVFilterContext
*ctx
)
50 FadeContext
*s
= ctx
->priv
;
52 s
->fade_per_frame
= (1 << 16) / s
->nb_frames
;
53 if (s
->type
== FADE_IN
) {
55 } else if (s
->type
== FADE_OUT
) {
56 s
->fade_per_frame
= -s
->fade_per_frame
;
57 s
->factor
= (1 << 16);
59 s
->stop_frame
= s
->start_frame
+ s
->nb_frames
;
61 av_log(ctx
, AV_LOG_VERBOSE
,
62 "type:%s start_frame:%d nb_frames:%d\n",
63 s
->type
== FADE_IN
? "in" : "out", s
->start_frame
,
68 static int query_formats(AVFilterContext
*ctx
)
70 static const enum AVPixelFormat pix_fmts
[] = {
71 AV_PIX_FMT_YUV444P
, AV_PIX_FMT_YUV422P
, AV_PIX_FMT_YUV420P
,
72 AV_PIX_FMT_YUV411P
, AV_PIX_FMT_YUV410P
,
73 AV_PIX_FMT_YUVJ444P
, AV_PIX_FMT_YUVJ422P
, AV_PIX_FMT_YUVJ420P
,
74 AV_PIX_FMT_YUV440P
, AV_PIX_FMT_YUVJ440P
,
75 AV_PIX_FMT_RGB24
, AV_PIX_FMT_BGR24
,
79 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
83 static int config_props(AVFilterLink
*inlink
)
85 FadeContext
*s
= inlink
->dst
->priv
;
86 const AVPixFmtDescriptor
*pixdesc
= av_pix_fmt_desc_get(inlink
->format
);
88 s
->hsub
= pixdesc
->log2_chroma_w
;
89 s
->vsub
= pixdesc
->log2_chroma_h
;
91 s
->bpp
= av_get_bits_per_pixel(pixdesc
) >> 3;
95 static int filter_slice_luma(AVFilterContext
*ctx
, void *arg
, int jobnr
,
98 FadeContext
*s
= ctx
->priv
;
100 int slice_h
= frame
->height
/ nb_jobs
;
101 int slice_start
= jobnr
* slice_h
;
102 int slice_end
= (jobnr
== nb_jobs
- 1) ? frame
->height
: (jobnr
+ 1) * slice_h
;
105 for (i
= slice_start
; i
< slice_end
; i
++) {
106 uint8_t *p
= frame
->data
[0] + i
* frame
->linesize
[0];
107 for (j
= 0; j
< frame
->width
* s
->bpp
; j
++) {
108 /* s->factor is using 16 lower-order bits for decimal
109 * places. 32768 = 1 << 15, it is an integer representation
110 * of 0.5 and is for rounding. */
111 *p
= (*p
* s
->factor
+ 32768) >> 16;
119 static int filter_slice_chroma(AVFilterContext
*ctx
, void *arg
, int jobnr
,
122 FadeContext
*s
= ctx
->priv
;
123 AVFrame
*frame
= arg
;
124 int slice_h
= FFALIGN(frame
->height
/ nb_jobs
, 1 << s
->vsub
);
125 int slice_start
= jobnr
* slice_h
;
126 int slice_end
= (jobnr
== nb_jobs
- 1) ? frame
->height
:
127 FFMIN((jobnr
+ 1) * slice_h
, frame
->height
);
130 for (plane
= 1; plane
< 3; plane
++) {
131 for (i
= slice_start
; i
< slice_end
; i
++) {
132 uint8_t *p
= frame
->data
[plane
] + (i
>> s
->vsub
) * frame
->linesize
[plane
];
133 for (j
= 0; j
< frame
->width
>> s
->hsub
; j
++) {
134 /* 8421367 = ((128 << 1) + 1) << 15. It is an integer
135 * representation of 128.5. The .5 is for rounding
137 *p
= ((*p
- 128) * s
->factor
+ 8421367) >> 16;
146 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
148 AVFilterContext
*ctx
= inlink
->dst
;
149 FadeContext
*s
= ctx
->priv
;
151 if (s
->factor
< UINT16_MAX
) {
152 /* luma or rgb plane */
153 ctx
->internal
->execute(ctx
, filter_slice_luma
, frame
, NULL
,
154 FFMIN(frame
->height
, ctx
->graph
->nb_threads
));
156 if (frame
->data
[1] && frame
->data
[2]) {
158 ctx
->internal
->execute(ctx
, filter_slice_chroma
, frame
, NULL
,
159 FFMIN(frame
->height
, ctx
->graph
->nb_threads
));
163 if (s
->frame_index
>= s
->start_frame
&&
164 s
->frame_index
<= s
->stop_frame
)
165 s
->factor
+= s
->fade_per_frame
;
166 s
->factor
= av_clip_uint16(s
->factor
);
169 return ff_filter_frame(inlink
->dst
->outputs
[0], frame
);
172 #define OFFSET(x) offsetof(FadeContext, x)
173 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM
174 static const AVOption options
[] = {
175 { "type", "'in' or 'out' for fade-in/fade-out", OFFSET(type
), AV_OPT_TYPE_INT
, { .i64
= FADE_IN
}, FADE_IN
, FADE_OUT
, FLAGS
, "type" },
176 { "in", "fade-in", 0, AV_OPT_TYPE_CONST
, { .i64
= FADE_IN
}, .unit
= "type" },
177 { "out", "fade-out", 0, AV_OPT_TYPE_CONST
, { .i64
= FADE_OUT
}, .unit
= "type" },
178 { "start_frame", "Number of the first frame to which to apply the effect.",
179 OFFSET(start_frame
), AV_OPT_TYPE_INT
, { .i64
= 0 }, 0, INT_MAX
, FLAGS
},
180 { "nb_frames", "Number of frames to which the effect should be applied.",
181 OFFSET(nb_frames
), AV_OPT_TYPE_INT
, { .i64
= 1 }, 0, INT_MAX
, FLAGS
},
185 static const AVClass fade_class
= {
186 .class_name
= "fade",
187 .item_name
= av_default_item_name
,
189 .version
= LIBAVUTIL_VERSION_INT
,
192 static const AVFilterPad avfilter_vf_fade_inputs
[] = {
195 .type
= AVMEDIA_TYPE_VIDEO
,
196 .config_props
= config_props
,
197 .get_video_buffer
= ff_null_get_video_buffer
,
198 .filter_frame
= filter_frame
,
204 static const AVFilterPad avfilter_vf_fade_outputs
[] = {
207 .type
= AVMEDIA_TYPE_VIDEO
,
212 AVFilter ff_vf_fade
= {
214 .description
= NULL_IF_CONFIG_SMALL("Fade in/out input video"),
216 .priv_size
= sizeof(FadeContext
),
217 .priv_class
= &fade_class
,
218 .query_formats
= query_formats
,
220 .inputs
= avfilter_vf_fade_inputs
,
221 .outputs
= avfilter_vf_fade_outputs
,
222 .flags
= AVFILTER_FLAG_SLICE_THREADS
,