X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Fvf_fade.c;h=7252a1200b6aadaad8e3bd3a9c22b7c29101489c;hb=0d602615ab58b14859dc915b94385cd79e21a87e;hp=6c2a23dac3080e77ba5daad0ad2d6bd468bc3b6a;hpb=173715d2918a8b2674e2d93e74d36df037ce4409;p=ffmpeg diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c index 6c2a23dac30..7252a1200b6 100644 --- a/libavfilter/vf_fade.c +++ b/libavfilter/vf_fade.c @@ -25,46 +25,113 @@ * based heavily on vf_negate.c by Bobby Bingham */ +#include "libavutil/avstring.h" +#include "libavutil/eval.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "drawutils.h" +#include "internal.h" typedef struct { + const AVClass *class; int factor, fade_per_frame; - unsigned int frame_index, start_frame, stop_frame; + unsigned int frame_index, start_frame, stop_frame, nb_frames; int hsub, vsub, bpp; + unsigned int black_level, black_level_scaled; + + char *type; } FadeContext; +#define OFFSET(x) offsetof(FadeContext, x) + +static const AVOption fade_options[] = { + { "type", "set the fade direction", OFFSET(type), AV_OPT_TYPE_STRING, {.str = "in" }, CHAR_MIN, CHAR_MAX }, + { "t", "set the fade direction", OFFSET(type), AV_OPT_TYPE_STRING, {.str = "in" }, CHAR_MIN, CHAR_MAX }, + { "start_frame", "set expression of frame to start fading", OFFSET(start_frame), AV_OPT_TYPE_INT, {.dbl = 0 }, 0, INT_MAX }, + { "s", "set expression of frame to start fading", OFFSET(start_frame), AV_OPT_TYPE_INT, {.dbl = 0 }, 0, INT_MAX }, + { "nb_frames", "set expression for fade duration in frames", OFFSET(nb_frames), AV_OPT_TYPE_INT, {.dbl = 25 }, 0, INT_MAX }, + { "n", "set expression for fade duration in frames", OFFSET(nb_frames), AV_OPT_TYPE_INT, {.dbl = 25 }, 0, INT_MAX }, + {NULL}, +}; + +static const char *fade_get_name(void *ctx) +{ + return "fade"; +} + +static const AVClass fade_class = { + "FadeContext", + fade_get_name, + fade_options +}; + static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) { FadeContext *fade = ctx->priv; - unsigned int nb_frames; - char in_out[4]; + int ret = 0; + char *args1, *expr, *bufptr = NULL; - 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); + fade->class = &fade_class; + av_opt_set_defaults(fade); + + if (!(args1 = av_strdup(args))) { + ret = AVERROR(ENOMEM); + goto end; } - nb_frames = nb_frames ? nb_frames : 1; - fade->fade_per_frame = (1 << 16) / nb_frames; - if (!strcmp(in_out, "in")) + if (expr = av_strtok(args1, ":", &bufptr)) { + if (!(fade->type = av_strdup(expr))) { + ret = AVERROR(ENOMEM); + goto end; + } + } + if (expr = av_strtok(NULL, ":", &bufptr)) { + if ((ret = av_opt_set(fade, "start_frame", expr, 0)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Invalid value '%s' for start_frame option\n", expr); + return ret; + } + } + if (expr = av_strtok(NULL, ":", &bufptr)) { + if ((ret = av_opt_set(fade, "nb_frames", expr, 0)) < 0) { + av_log(ctx, AV_LOG_ERROR, + "Invalid value '%s' for nb_frames option\n", expr); + return ret; + } + } + + if (bufptr && (ret = av_set_options_string(fade, bufptr, "=", ":")) < 0) + goto end; + + fade->fade_per_frame = (1 << 16) / fade->nb_frames; + if (!strcmp(fade->type, "in")) fade->factor = 0; - else if (!strcmp(in_out, "out")) { + else if (!strcmp(fade->type, "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); + "Type argument must be 'in' or 'out' but '%s' was specified\n", fade->type); + ret = AVERROR(EINVAL); + goto end; } - fade->stop_frame = fade->start_frame + nb_frames; + fade->stop_frame = fade->start_frame + fade->nb_frames; av_log(ctx, AV_LOG_INFO, "type:%s start_frame:%d nb_frames:%d\n", - in_out, fade->start_frame, nb_frames); - return 0; + fade->type, fade->start_frame, fade->nb_frames); + +end: + av_free(args1); + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + FadeContext *fade = ctx->priv; + + av_freep(&fade->type); } static int query_formats(AVFilterContext *ctx) @@ -82,6 +149,13 @@ static int query_formats(AVFilterContext *ctx) return 0; } +const static enum PixelFormat studio_level_pix_fmts[] = { + PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV420P, + PIX_FMT_YUV411P, PIX_FMT_YUV410P, + PIX_FMT_YUV440P, + PIX_FMT_NONE +}; + static int config_props(AVFilterLink *inlink) { FadeContext *fade = inlink->dst->priv; @@ -91,6 +165,11 @@ static int config_props(AVFilterLink *inlink) fade->vsub = pixdesc->log2_chroma_h; fade->bpp = av_get_bits_per_pixel(pixdesc) >> 3; + + fade->black_level = ff_fmt_is_in(inlink->format, studio_level_pix_fmts) ? 16 : 0; + /* 32768 = 1 << 15, it is an integer representation + * of 0.5 and is for rounding. */ + fade->black_level_scaled = (fade->black_level << 16) + 32768; return 0; } @@ -106,10 +185,8 @@ static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) 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; + /* fade->factor is using 16 lower-order bits for decimal places. */ + *p = ((*p - fade->black_level) * fade->factor + fade->black_level_scaled) >> 16; p++; } } @@ -151,10 +228,11 @@ AVFilter avfilter_vf_fade = { .name = "fade", .description = NULL_IF_CONFIG_SMALL("Fade in/out input video"), .init = init, + .uninit = uninit, .priv_size = sizeof(FadeContext), .query_formats = query_formats, - .inputs = (AVFilterPad[]) {{ .name = "default", + .inputs = (const AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_props, .get_video_buffer = avfilter_null_get_video_buffer, @@ -164,7 +242,7 @@ AVFilter avfilter_vf_fade = { .min_perms = AV_PERM_READ | AV_PERM_WRITE, .rej_perms = AV_PERM_PRESERVE, }, { .name = NULL}}, - .outputs = (AVFilterPad[]) {{ .name = "default", + .outputs = (const AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_VIDEO, }, { .name = NULL}}, };