vf_fade.c 6.01 KB
Newer Older
Brandon Mintern's avatar
Brandon Mintern committed
1 2 3 4
/*
 * Copyright (c) 2010 Brandon Mintern
 * Copyright (c) 2007 Bobby Bingham
 *
5
 * This file is part of Libav.
Brandon Mintern's avatar
Brandon Mintern committed
6
 *
7
 * Libav is free software; you can redistribute it and/or
Brandon Mintern's avatar
Brandon Mintern committed
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
 * Libav is distributed in the hope that it will be useful,
Brandon Mintern's avatar
Brandon Mintern committed
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 Libav; if not, write to the Free Software
Brandon Mintern's avatar
Brandon Mintern committed
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/common.h"
Brandon Mintern's avatar
Brandon Mintern committed
29 30
#include "libavutil/pixdesc.h"
#include "avfilter.h"
31
#include "formats.h"
32
#include "internal.h"
33
#include "video.h"
Brandon Mintern's avatar
Brandon Mintern committed
34 35 36 37 38 39 40

typedef struct {
    int factor, fade_per_frame;
    unsigned int frame_index, start_frame, stop_frame;
    int hsub, vsub, bpp;
} FadeContext;

41
static av_cold int init(AVFilterContext *ctx, const char *args)
Brandon Mintern's avatar
Brandon Mintern committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
{
    FadeContext *fade = ctx->priv;
    unsigned int nb_frames;
    char in_out[4];

    if (!args ||
        sscanf(args, " %3[^:]:%u:%u", in_out, &fade->start_frame, &nb_frames) != 3) {
        av_log(ctx, AV_LOG_ERROR,
               "Expected 3 arguments '(in|out):#:#':'%s'\n", args);
        return AVERROR(EINVAL);
    }

    nb_frames = nb_frames ? nb_frames : 1;
    fade->fade_per_frame = (1 << 16) / nb_frames;
    if (!strcmp(in_out, "in"))
        fade->factor = 0;
    else if (!strcmp(in_out, "out")) {
        fade->fade_per_frame = -fade->fade_per_frame;
        fade->factor = (1 << 16);
    } else {
        av_log(ctx, AV_LOG_ERROR,
               "first argument must be 'in' or 'out':'%s'\n", in_out);
        return AVERROR(EINVAL);
    }
    fade->stop_frame = fade->start_frame + nb_frames;

68
    av_log(ctx, AV_LOG_VERBOSE,
Brandon Mintern's avatar
Brandon Mintern committed
69 70 71 72 73 74 75
           "type:%s start_frame:%d nb_frames:%d\n",
           in_out, fade->start_frame, nb_frames);
    return 0;
}

static int query_formats(AVFilterContext *ctx)
{
76
    static const enum PixelFormat pix_fmts[] = {
Brandon Mintern's avatar
Brandon Mintern committed
77 78 79 80 81 82 83 84
        PIX_FMT_YUV444P,  PIX_FMT_YUV422P,  PIX_FMT_YUV420P,
        PIX_FMT_YUV411P,  PIX_FMT_YUV410P,
        PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
        PIX_FMT_YUV440P,  PIX_FMT_YUVJ440P,
        PIX_FMT_RGB24,    PIX_FMT_BGR24,
        PIX_FMT_NONE
    };

85
    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
Brandon Mintern's avatar
Brandon Mintern committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    return 0;
}

static int config_props(AVFilterLink *inlink)
{
    FadeContext *fade = inlink->dst->priv;
    const AVPixFmtDescriptor *pixdesc = &av_pix_fmt_descriptors[inlink->format];

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

    fade->bpp = av_get_bits_per_pixel(pixdesc) >> 3;
    return 0;
}

101
static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
Brandon Mintern's avatar
Brandon Mintern committed
102 103 104 105 106 107
{
    FadeContext *fade = inlink->dst->priv;
    AVFilterBufferRef *outpic = inlink->cur_buf;
    uint8_t *p;
    int i, j, plane;

108
    if (fade->factor < UINT16_MAX) {
Brandon Mintern's avatar
Brandon Mintern committed
109 110 111 112 113 114 115 116 117 118 119 120
        /* luma or rgb plane */
        for (i = 0; i < h; i++) {
            p = outpic->data[0] + (y+i) * outpic->linesize[0];
            for (j = 0; j < inlink->w * fade->bpp; j++) {
                /* fade->factor is using 16 lower-order bits for decimal
                 * places. 32768 = 1 << 15, it is an integer representation
                 * of 0.5 and is for rounding. */
                *p = (*p * fade->factor + 32768) >> 16;
                p++;
            }
        }

121
        if (outpic->data[1] && outpic->data[2]) {
Brandon Mintern's avatar
Brandon Mintern committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
            /* chroma planes */
            for (plane = 1; plane < 3; plane++) {
                for (i = 0; i < h; i++) {
                    p = outpic->data[plane] + ((y+i) >> fade->vsub) * outpic->linesize[plane];
                    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++;
                    }
                }
            }
        }
    }

138
    return ff_draw_slice(inlink->dst->outputs[0], y, h, slice_dir);
Brandon Mintern's avatar
Brandon Mintern committed
139 140
}

141
static int end_frame(AVFilterLink *inlink)
Brandon Mintern's avatar
Brandon Mintern committed
142 143
{
    FadeContext *fade = inlink->dst->priv;
144
    int ret;
Brandon Mintern's avatar
Brandon Mintern committed
145

146
    ret = ff_end_frame(inlink->dst->outputs[0]);
Brandon Mintern's avatar
Brandon Mintern committed
147 148 149 150 151 152

    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++;
153 154

    return ret;
Brandon Mintern's avatar
Brandon Mintern committed
155 156 157 158 159 160 161 162 163
}

AVFilter avfilter_vf_fade = {
    .name          = "fade",
    .description   = NULL_IF_CONFIG_SMALL("Fade in/out input video"),
    .init          = init,
    .priv_size     = sizeof(FadeContext),
    .query_formats = query_formats,

164 165 166 167 168 169 170 171 172 173 174 175 176
    .inputs    = (const AVFilterPad[]) {{ .name            = "default",
                                          .type            = AVMEDIA_TYPE_VIDEO,
                                          .config_props    = config_props,
                                          .get_video_buffer = ff_null_get_video_buffer,
                                          .start_frame      = ff_null_start_frame,
                                          .draw_slice      = draw_slice,
                                          .end_frame       = end_frame,
                                          .min_perms       = AV_PERM_READ | AV_PERM_WRITE,
                                          .rej_perms       = AV_PERM_PRESERVE, },
                                        { .name = NULL}},
    .outputs   = (const AVFilterPad[]) {{ .name            = "default",
                                          .type            = AVMEDIA_TYPE_VIDEO, },
                                        { .name = NULL}},
Brandon Mintern's avatar
Brandon Mintern committed
177
};