[FFmpeg-devel] [PATCH] vf_fade: fade alpha

Mark Himsley mark at mdsh.com
Sat Nov 5 22:53:35 CET 2011


On 05/11/2011 14:26, Stefano Sabatini wrote:
> On date Saturday 2011-11-05 02:01:02 +0000, Mark Himsley encoded:
>> add alpha fading
>>
>> --
>> Mark
>
>> diff --git a/doc/filters.texi b/doc/filters.texi
>> index a6110e4..70fbea7 100644
>> --- a/doc/filters.texi
>> +++ b/doc/filters.texi
>> @@ -1105,6 +1105,9 @@ See @var{start_frame}
>>   @item duration, d
>>   See @var{nb_frames}
>>
>> + at item alpha
>> +If set to 1, fade only alpha channel, if one exists on the input.
>> +Default value is 0.
>>   @end table
>>
>>   A few usage examples follow, usable too as test scenarios.
>> @@ -1120,6 +1123,9 @@ fade=in:0:25, fade=out:975:25
>>
>>   # make first 5 frames black, then fade in from frame 5-24
>>   fade=in:5:20
>> +
>> +# fade in alpha over first 25 frames of video
>> +fade=in:0:25:alpha=1
>>   @end example
>>
>>   @section fieldorder
>> diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c
>> index 6f750b4..8b7e70e 100644
>> --- a/libavfilter/vf_fade.c
>> +++ b/libavfilter/vf_fade.c
>> @@ -39,8 +39,12 @@ typedef struct {
>>       unsigned int frame_index, start_frame, stop_frame;
>>       int hsub, vsub, bpp;
>>       unsigned int black_level, black_level_scaled;
>> +    uint8_t is_packed_rgb;
>> +    uint8_t rgba_map[4];
>> +    uint8_t alpha;
>>
>>       char *type, *start_expr, *count_expr;
>
>> +    double alpha_expr;
>
> double alpha_expr =>  int alpha

D'oh.

>>   } FadeContext;
>>
>>   #define OFFSET(x) offsetof(FadeContext, x)
>> @@ -52,6 +56,7 @@ static const AVOption fade_options[] = {
>>       { "i",        "set expression of frame to start fading",    OFFSET(start_expr), AV_OPT_TYPE_STRING, {.str = "0"  }, CHAR_MIN, CHAR_MAX },
>>       { "duration", "set expression for fade duration in frames", OFFSET(count_expr), AV_OPT_TYPE_STRING, {.str = "25" }, CHAR_MIN, CHAR_MAX },
>>       { "d",        "set expression for fade duration in frames", OFFSET(count_expr), AV_OPT_TYPE_STRING, {.str = "25" }, CHAR_MIN, CHAR_MAX },
>> +    { "alpha",    "fade alpha if it's available on the input",  OFFSET(alpha_expr), AV_OPT_TYPE_INT,    {.dbl = 0    },        0,        1 },
>>       {NULL},
>>   };
>>
>> @@ -126,10 +131,11 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
>>           goto fail;
>>       }
>>       fade->stop_frame = fade->start_frame + nb_frames;
>> +    fade->alpha = !!fade->alpha_expr;
>>
>>       av_log(ctx, AV_LOG_INFO,
>> -           "type:%s start_frame:%d nb_frames:%d\n",
>> -           fade->type, fade->start_frame, nb_frames);
>> +           "type:%s start_frame:%d nb_frames:%d alpha:%d\n",
>> +           fade->type, fade->start_frame, nb_frames, fade->alpha);
>>
>>   end:
>>       av_free(args1);
>> @@ -158,7 +164,10 @@ static int query_formats(AVFilterContext *ctx)
>>           PIX_FMT_YUV411P,  PIX_FMT_YUV410P,
>>           PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
>>           PIX_FMT_YUV440P,  PIX_FMT_YUVJ440P,
>> +        PIX_FMT_YUVA420P,
>>           PIX_FMT_RGB24,    PIX_FMT_BGR24,
>> +        PIX_FMT_ARGB,     PIX_FMT_ABGR,
>> +        PIX_FMT_RGBA,     PIX_FMT_BGRA,
>>           PIX_FMT_NONE
>>       };
>>
>> @@ -173,6 +182,13 @@ const static enum PixelFormat studio_level_pix_fmts[] = {
>>       PIX_FMT_NONE
>>   };
>>
>> +static enum PixelFormat alpha_pix_fmts[] = {
>> +    PIX_FMT_YUVA420P,
>> +    PIX_FMT_ARGB, PIX_FMT_ABGR,
>> +    PIX_FMT_RGBA, PIX_FMT_BGRA,
>> +    PIX_FMT_NONE
>> +};
>> +
>>   static int config_props(AVFilterLink *inlink)
>>   {
>>       FadeContext *fade = inlink->dst->priv;
>> @@ -182,14 +198,36 @@ static int config_props(AVFilterLink *inlink)
>>       fade->vsub = pixdesc->log2_chroma_h;
>>
>>       fade->bpp = av_get_bits_per_pixel(pixdesc)>>  3;
>> +    fade->alpha = fade->alpha ? ff_fmt_is_in(inlink->format, alpha_pix_fmts) : 0;
>> +    fade->is_packed_rgb = ff_fill_rgba_map(fade->rgba_map, inlink->format)>= 0;
>>
>> -    fade->black_level = ff_fmt_is_in(inlink->format, studio_level_pix_fmts) ? 16 : 0;
>> +    /* CCIR601/709 black level unless input is RGB or has alpha */
>
>> +    fade->black_level = ff_fmt_is_in(inlink->format, studio_level_pix_fmts) ?
>> +            fade->alpha ? 0 : 16 : 0;
>
> simpler:
> fade->black_level =
>       ff_fmt_is_in(inlink->format, studio_level_pix_fmts) || fade->alpha ? 0 : 16;

D'oh - I should have read my comment, which says what you've written.

>>       /* 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;
>>   }
>>
>> +static void fade_luma(int y, int h, int w, int ff, int bl, int bls,
>
> please more meaningful names or doxygen them
> the function may be renamed fade_plane()

Yep.

>> +        uint8_t offset, uint8_t step, int bpp,
>> +        uint8_t *data, int linesize)
>> +{
>> +    uint8_t *p;
>> +    int i, j;
>> +
>> +    /* luma, alpha or rgb plane */
>> +    for (i = 0; i<  h; i++) {
>> +        p = data + offset + (y+i) * linesize;
>> +        for (j = 0; j<  w * bpp; j++) {
>> +            /* fade->factor is using 16 lower-order bits for decimal places. */
>> +            *p = ((*p - bl) * ff + bls)>>  16;
>> +            p+=step;
>> +        }
>> +    }
>> +}
>> +
>>   static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
>>   {
>>       FadeContext *fade = inlink->dst->priv;
>> @@ -198,16 +236,15 @@ static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
>>       int i, j, plane;
>>
>>       if (fade->factor<  UINT16_MAX) {
>> +        if (fade->alpha) {
>
>> +            // alpha only
>> +            fade_luma( y, h, inlink->w, fade->factor, fade->black_level, fade->black_level_scaled,
>> +                    fade->is_packed_rgb ? fade->rgba_map[3] : 0, fade->is_packed_rgb ? 4 : 1, 1,
>> +                    outpic->data[fade->is_packed_rgb ? 0 : 3], outpic->linesize[fade->is_packed_rgb ? 0 : 3]);
>
> slightly more readable:
>           plane = fade->is_packed_rgb ? 0 : 3;
>           fade_luma(y, h, inlink->w, fade->factor, fade->black_level, fade->black_level_scaled,
>                     fade->is_packed_rgb ? fade->rgba_map[3] : 0, // offset
>                     fade->is_packed_rgb ? 4 : 1,                 // pixstep
>                     1, outpic->data[plane], outpic->linesize[plane]);

Ok.

One question. Should fade->bpp be used for the alpha plane?

> maybe you can define R G B A Y macros and use them in place of 0 1 2 3 0.
>
>> +        } else {
>>           /* 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. */
>> -                *p = ((*p - fade->black_level) * fade->factor + fade->black_level_scaled)>>  16;
>> -                p++;
>> -            }
>> -        }
>> -
>> +        fade_luma( y, h, inlink->w, fade->factor, fade->black_level, fade->black_level_scaled,
>> +                0, 1, fade->bpp, outpic->data[0], outpic->linesize[0]);
>>           if (outpic->data[1]&&  outpic->data[2]) {
>>               /* chroma planes */
>>               for (plane = 1; plane<  3; plane++) {
>> @@ -223,6 +260,7 @@ static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
>>                   }
>>               }
>>           }
>> +        }
>>       }

Thanks for the review.

I'll send updated patches.

-- 
Mark


More information about the ffmpeg-devel mailing list