vf_fade.c 9.1 KB
Newer Older
B
Brandon Mintern 已提交
1 2 3 4
/*
 * Copyright (c) 2010 Brandon Mintern
 * Copyright (c) 2007 Bobby Bingham
 *
5
 * This file is part of FFmpeg.
B
Brandon Mintern 已提交
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
B
Brandon Mintern 已提交
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
B
Brandon Mintern 已提交
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
B
Brandon Mintern 已提交
19 20 21 22 23 24 25 26 27
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
 * @file
 * video fade filter
 * based heavily on vf_negate.c by Bobby Bingham
 */

28
#include "libavutil/avstring.h"
29
#include "libavutil/common.h"
30 31
#include "libavutil/eval.h"
#include "libavutil/opt.h"
B
Brandon Mintern 已提交
32 33
#include "libavutil/pixdesc.h"
#include "avfilter.h"
34
#include "drawutils.h"
35
#include "internal.h"
36
#include "formats.h"
37
#include "internal.h"
38
#include "video.h"
B
Brandon Mintern 已提交
39

40 41 42 43 44 45 46 47 48
#define R 0
#define G 1
#define B 2
#define A 3

#define Y 0
#define U 1
#define V 2

49 50 51
#define FADE_IN  0
#define FADE_OUT 1

B
Brandon Mintern 已提交
52
typedef struct {
53
    const AVClass *class;
54
    int type;
B
Brandon Mintern 已提交
55
    int factor, fade_per_frame;
56 57
    int start_frame, nb_frames;
    unsigned int frame_index, stop_frame;
B
Brandon Mintern 已提交
58
    int hsub, vsub, bpp;
59
    unsigned int black_level, black_level_scaled;
60 61 62
    uint8_t is_packed_rgb;
    uint8_t rgba_map[4];
    int alpha;
63

B
Brandon Mintern 已提交
64 65
} FadeContext;

66
static av_cold int init(AVFilterContext *ctx)
B
Brandon Mintern 已提交
67 68 69
{
    FadeContext *fade = ctx->priv;

70
    fade->fade_per_frame = (1 << 16) / fade->nb_frames;
71
    if (fade->type == FADE_IN) {
B
Brandon Mintern 已提交
72
        fade->factor = 0;
73
    } else if (fade->type == FADE_OUT) {
B
Brandon Mintern 已提交
74 75 76
        fade->fade_per_frame = -fade->fade_per_frame;
        fade->factor = (1 << 16);
    }
77
    fade->stop_frame = fade->start_frame + fade->nb_frames;
B
Brandon Mintern 已提交
78

79
    av_log(ctx, AV_LOG_VERBOSE,
80
           "type:%s start_frame:%d nb_frames:%d alpha:%d\n",
81
           fade->type == FADE_IN ? "in" : "out", fade->start_frame,
82
           fade->nb_frames, fade->alpha);
83
    return 0;
84 85
}

B
Brandon Mintern 已提交
86 87
static int query_formats(AVFilterContext *ctx)
{
88 89 90 91 92
    static const enum AVPixelFormat pix_fmts[] = {
        AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
        AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
        AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P,
        AV_PIX_FMT_YUV440P,  AV_PIX_FMT_YUVJ440P,
93
        AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
94
        AV_PIX_FMT_RGB24,    AV_PIX_FMT_BGR24,
95 96
        AV_PIX_FMT_ARGB,     AV_PIX_FMT_ABGR,
        AV_PIX_FMT_RGBA,     AV_PIX_FMT_BGRA,
97
        AV_PIX_FMT_NONE
B
Brandon Mintern 已提交
98 99
    };

100
    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
B
Brandon Mintern 已提交
101 102 103
    return 0;
}

104 105 106 107 108
const static enum AVPixelFormat studio_level_pix_fmts[] = {
    AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
    AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
    AV_PIX_FMT_YUV440P,
    AV_PIX_FMT_NONE
109 110
};

B
Brandon Mintern 已提交
111 112 113
static int config_props(AVFilterLink *inlink)
{
    FadeContext *fade = inlink->dst->priv;
114
    const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(inlink->format);
B
Brandon Mintern 已提交
115 116 117 118 119

    fade->hsub = pixdesc->log2_chroma_w;
    fade->vsub = pixdesc->log2_chroma_h;

    fade->bpp = av_get_bits_per_pixel(pixdesc) >> 3;
120
    fade->alpha &= pixdesc->flags & PIX_FMT_ALPHA;
121
    fade->is_packed_rgb = ff_fill_rgba_map(fade->rgba_map, inlink->format) >= 0;
122

123
    /* use CCIR601/709 black level for studio-level pixel non-alpha components */
124
    fade->black_level =
125
            ff_fmt_is_in(inlink->format, studio_level_pix_fmts) && !fade->alpha ? 16 : 0;
126 127 128
    /* 32768 = 1 << 15, it is an integer representation
     * of 0.5 and is for rounding. */
    fade->black_level_scaled = (fade->black_level << 16) + 32768;
B
Brandon Mintern 已提交
129 130 131
    return 0;
}

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
static void fade_plane(int y, int h, int w,
                       int fade_factor, int black_level, int black_level_scaled,
                       uint8_t offset, uint8_t step, int bytes_per_plane,
                       uint8_t *data, int line_size)
{
    uint8_t *p;
    int i, j;

    /* luma, alpha or rgb plane */
    for (i = 0; i < h; i++) {
        p = data + offset + (y+i) * line_size;
        for (j = 0; j < w * bytes_per_plane; j++) {
            /* fade->factor is using 16 lower-order bits for decimal places. */
            *p = ((*p - black_level) * fade_factor + black_level_scaled) >> 16;
            p+=step;
        }
    }
}

A
Anton Khirnov 已提交
151
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
B
Brandon Mintern 已提交
152 153 154 155 156
{
    FadeContext *fade = inlink->dst->priv;
    uint8_t *p;
    int i, j, plane;

157
    if (fade->factor < UINT16_MAX) {
158 159 160 161
        if (fade->alpha) {
            // alpha only
            plane = fade->is_packed_rgb ? 0 : A; // alpha is on plane 0 for packed formats
                                                 // or plane 3 for planar formats
162
            fade_plane(0, frame->height, inlink->w,
163 164 165
                       fade->factor, fade->black_level, fade->black_level_scaled,
                       fade->is_packed_rgb ? fade->rgba_map[A] : 0, // alpha offset for packed formats
                       fade->is_packed_rgb ? 4 : 1,                 // pixstep for 8 bit packed formats
A
Anton Khirnov 已提交
166
                       1, frame->data[plane], frame->linesize[plane]);
167
        } else {
168
            /* luma or rgb plane */
169
            fade_plane(0, frame->height, inlink->w,
170 171
                       fade->factor, fade->black_level, fade->black_level_scaled,
                       0, 1, // offset & pixstep for Y plane or RGB packed format
A
Anton Khirnov 已提交
172 173
                       fade->bpp, frame->data[0], frame->linesize[0]);
            if (frame->data[1] && frame->data[2]) {
174 175
                /* chroma planes */
                for (plane = 1; plane < 3; plane++) {
176
                    for (i = 0; i < frame->height; i++) {
A
Anton Khirnov 已提交
177
                        p = frame->data[plane] + (i >> fade->vsub) * frame->linesize[plane];
178 179 180 181 182 183 184
                        for (j = 0; j < inlink->w >> fade->hsub; j++) {
                            /* 8421367 = ((128 << 1) + 1) << 15. It is an integer
                             * representation of 128.5. The .5 is for rounding
                             * purposes. */
                            *p = ((*p - 128) * fade->factor + 8421367) >> 16;
                            p++;
                        }
B
Brandon Mintern 已提交
185 186 187 188 189 190 191 192 193 194 195
                    }
                }
            }
        }
    }

    if (fade->frame_index >= fade->start_frame &&
        fade->frame_index <= fade->stop_frame)
        fade->factor += fade->fade_per_frame;
    fade->factor = av_clip_uint16(fade->factor);
    fade->frame_index++;
196

A
Anton Khirnov 已提交
197
    return ff_filter_frame(inlink->dst->outputs[0], frame);
B
Brandon Mintern 已提交
198 199
}

200

201
#define OFFSET(x) offsetof(FadeContext, x)
202 203 204
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM

static const AVOption fade_options[] = {
205
    { "type", "'in' or 'out' for fade-in/fade-out", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = FADE_IN }, FADE_IN, FADE_OUT, FLAGS, "type" },
206
    { "t",    "'in' or 'out' for fade-in/fade-out", OFFSET(type), AV_OPT_TYPE_INT, { .i64 = FADE_IN }, FADE_IN, FADE_OUT, FLAGS, "type" },
207 208 209 210
        { "in",  "fade-in",  0, AV_OPT_TYPE_CONST, { .i64 = FADE_IN },  .unit = "type" },
        { "out", "fade-out", 0, AV_OPT_TYPE_CONST, { .i64 = FADE_OUT }, .unit = "type" },
    { "start_frame", "Number of the first frame to which to apply the effect.",
                                                    OFFSET(start_frame), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
211 212
    { "s",           "Number of the first frame to which to apply the effect.",
                                                    OFFSET(start_frame), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
213
    { "nb_frames",   "Number of frames to which the effect should be applied.",
214 215 216 217
                                                    OFFSET(nb_frames),   AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS },
    { "n",           "Number of frames to which the effect should be applied.",
                                                    OFFSET(nb_frames),   AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS },
    { "alpha",       "fade alpha if it is available on the input", OFFSET(alpha),       AV_OPT_TYPE_INT, {.i64 = 0    }, 0,       1, FLAGS },
218 219 220
    { NULL },
};

221
AVFILTER_DEFINE_CLASS(fade);
222

223 224 225 226 227 228
static const AVFilterPad avfilter_vf_fade_inputs[] = {
    {
        .name             = "default",
        .type             = AVMEDIA_TYPE_VIDEO,
        .config_props     = config_props,
        .get_video_buffer = ff_null_get_video_buffer,
A
Anton Khirnov 已提交
229
        .filter_frame     = filter_frame,
A
Anton Khirnov 已提交
230
        .needs_writable   = 1,
231 232 233 234 235 236 237 238 239 240 241 242
    },
    { NULL }
};

static const AVFilterPad avfilter_vf_fade_outputs[] = {
    {
        .name = "default",
        .type = AVMEDIA_TYPE_VIDEO,
    },
    { NULL }
};

B
Brandon Mintern 已提交
243 244
AVFilter avfilter_vf_fade = {
    .name          = "fade",
245
    .description   = NULL_IF_CONFIG_SMALL("Fade in/out input video."),
B
Brandon Mintern 已提交
246 247
    .init          = init,
    .priv_size     = sizeof(FadeContext),
248
    .priv_class    = &fade_class,
B
Brandon Mintern 已提交
249 250
    .query_formats = query_formats,

251 252
    .inputs    = avfilter_vf_fade_inputs,
    .outputs   = avfilter_vf_fade_outputs,
B
Brandon Mintern 已提交
253
};