+static int filter_slice_alpha16(AVFilterContext *ctx, void *arg, int jobnr,
+ int nb_jobs)
+{
+ FadeContext *s = ctx->priv;
+ AVFrame *frame = arg;
+ int plane = s->is_packed_rgb ? 0 : A;
+ int slice_start = (frame->height * jobnr ) / nb_jobs;
+ int slice_end = (frame->height * (jobnr+1)) / nb_jobs;
+ int i, j;
+
+ for (i = slice_start; i < slice_end; i++) {
+ uint16_t *p = (uint16_t *)(frame->data[plane] + i * frame->linesize[plane]) + s->is_packed_rgb*s->rgba_map[A];
+ int step = s->is_packed_rgb ? 4 : 1;
+ for (j = 0; j < frame->width; j++) {
+ /* s->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 - s->black_level) * s->factor + s->black_level_scaled) >> 16;
+ p += step;
+ }
+ }
+
+ return 0;
+}
+
+static int config_props(AVFilterLink *inlink)
+{
+ FadeContext *s = inlink->dst->priv;
+ const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(inlink->format);
+
+ s->hsub = pixdesc->log2_chroma_w;
+ s->vsub = pixdesc->log2_chroma_h;
+
+ ff_fill_rgba_map(s->rgba_map, inlink->format);
+
+ s->depth = pixdesc->comp[0].depth;
+ s->bpp = pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR ?
+ 1 :
+ av_get_bits_per_pixel(pixdesc) >> 3;
+ s->alpha &= !!(pixdesc->flags & AV_PIX_FMT_FLAG_ALPHA);
+ s->is_planar = pixdesc->flags & AV_PIX_FMT_FLAG_PLANAR;
+ s->is_rgb = pixdesc->flags & AV_PIX_FMT_FLAG_RGB;
+ s->is_packed_rgb = !s->is_planar && s->is_rgb;
+
+ /* use CCIR601/709 black level for studio-level pixel non-alpha components */
+ s->black_level =
+ ff_fmt_is_in(inlink->format, studio_level_pix_fmts) && !s->alpha ? 16 * (1 << (s->depth - 8)): 0;
+ /* 32768 = 1 << 15, it is an integer representation
+ * of 0.5 and is for rounding. */
+ s->black_level_scaled = (s->black_level << 16) + 32768;
+
+ s->filter_slice_luma = s->depth <= 8 ? filter_slice_luma : filter_slice_luma16;
+ s->filter_slice_chroma = s->depth <= 8 ? filter_slice_chroma : filter_slice_chroma16;
+ s->filter_slice_alpha = s->depth <= 8 ? filter_slice_alpha : filter_slice_alpha16;
+
+ return 0;
+}
+