]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_fieldmatch.c
cbs_h265: Ensure that a predicted RPS doesn't contain too many pictures
[ffmpeg] / libavfilter / vf_fieldmatch.c
index 4f10ed7ccd277fe909745eb08d5d73c0c68e6202..fa4aa8239cca04973bc5ad00f4713f4aa8fb1155 100644 (file)
@@ -37,6 +37,7 @@
 #include "libavutil/opt.h"
 #include "libavutil/timestamp.h"
 #include "avfilter.h"
+#include "filters.h"
 #include "internal.h"
 
 #define INPUT_MAIN     0
@@ -79,6 +80,7 @@ typedef struct FieldMatchContext {
     AVFrame *prv2, *src2, *nxt2;    ///< sliding window of the optional second stream
     int got_frame[2];               ///< frame request flag for each input stream
     int hsub, vsub;                 ///< chroma subsampling values
+    int bpc;                        ///< bytes per component
     uint32_t eof;                   ///< bitmask for end of stream
     int64_t lastscdiff;
     int64_t lastn;
@@ -613,7 +615,7 @@ static void copy_fields(const FieldMatchContext *fm, AVFrame *dst,
         const int nb_copy_fields = (plane_h >> 1) + (field ? 0 : (plane_h & 1));
         av_image_copy_plane(dst->data[plane] + field*dst->linesize[plane], dst->linesize[plane] << 1,
                             src->data[plane] + field*src->linesize[plane], src->linesize[plane] << 1,
-                            get_width(fm, src, plane), nb_copy_fields);
+                            get_width(fm, src, plane) * fm->bpc, nb_copy_fields);
     }
 }
 
@@ -677,7 +679,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
     AVFilterLink *outlink = ctx->outputs[0];
     FieldMatchContext *fm = ctx->priv;
     int combs[] = { -1, -1, -1, -1, -1 };
-    int order, field, i, match, sc = 0;
+    int order, field, i, match, sc = 0, ret = 0;
     const int *fxo;
     AVFrame *gen_frames[] = { NULL, NULL, NULL, NULL, NULL };
     AVFrame *dst;
@@ -697,9 +699,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
         av_assert0(prv && src && nxt);                          \
 } while (0)
     if (FF_INLINK_IDX(inlink) == INPUT_MAIN) {
+        av_assert0(fm->got_frame[INPUT_MAIN] == 0);
         SLIDING_FRAME_WINDOW(fm->prv, fm->src, fm->nxt);
         fm->got_frame[INPUT_MAIN] = 1;
     } else {
+        av_assert0(fm->got_frame[INPUT_CLEANSRC] == 0);
         SLIDING_FRAME_WINDOW(fm->prv2, fm->src2, fm->nxt2);
         fm->got_frame[INPUT_CLEANSRC] = 1;
     }
@@ -721,16 +725,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             if (i > mN && fm->combdbg == COMBDBG_PCN)
                 break;
             gen_frames[i] = create_weave_frame(ctx, i, field, fm->prv, fm->src, fm->nxt);
-            if (!gen_frames[i])
-                return AVERROR(ENOMEM);
+            if (!gen_frames[i]) {
+                ret = AVERROR(ENOMEM);
+                goto fail;
+            }
             combs[i] = calc_combed_score(fm, gen_frames[i]);
         }
         av_log(ctx, AV_LOG_INFO, "COMBS: %3d %3d %3d %3d %3d\n",
                combs[0], combs[1], combs[2], combs[3], combs[4]);
     } else {
         gen_frames[mC] = av_frame_clone(fm->src);
-        if (!gen_frames[mC])
-            return AVERROR(ENOMEM);
+        if (!gen_frames[mC]) {
+            ret = AVERROR(ENOMEM);
+            goto fail;
+        }
     }
 
     /* p/c selection and optional 3-way p/c/n matches */
@@ -797,10 +805,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
             gen_frames[match] = NULL;
         }
     }
-    if (!dst)
-        return AVERROR(ENOMEM);
-    for (i = 0; i < FF_ARRAY_ELEMS(gen_frames); i++)
-        av_frame_free(&gen_frames[i]);
+    if (!dst) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
 
     /* mark the frame we are unable to match properly as interlaced so a proper
      * de-interlacer can take the relay */
@@ -815,53 +823,110 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
            " match=%d combed=%s\n", sc, combs[0], combs[1], combs[2], combs[3], combs[4],
            fm->combpel, match, dst->interlaced_frame ? "YES" : "NO");
 
-    return ff_filter_frame(outlink, dst);
-}
-
-static int request_inlink(AVFilterContext *ctx, int lid)
-{
-    int ret = 0;
-    FieldMatchContext *fm = ctx->priv;
+fail:
+    for (i = 0; i < FF_ARRAY_ELEMS(gen_frames); i++)
+        av_frame_free(&gen_frames[i]);
 
-    if (!fm->got_frame[lid]) {
-        AVFilterLink *inlink = ctx->inputs[lid];
-        ret = ff_request_frame(inlink);
-        if (ret == AVERROR_EOF) { // flushing
-            fm->eof |= 1 << lid;
-            ret = filter_frame(inlink, NULL);
-        }
-    }
+    if (ret >= 0)
+        return ff_filter_frame(outlink, dst);
     return ret;
 }
 
-static int request_frame(AVFilterLink *outlink)
+static int activate(AVFilterContext *ctx)
 {
-    int ret;
-    AVFilterContext *ctx = outlink->src;
     FieldMatchContext *fm = ctx->priv;
-    const uint32_t eof_mask = 1<<INPUT_MAIN | fm->ppsrc<<INPUT_CLEANSRC;
+    AVFrame *frame = NULL;
+    int ret = 0, status;
+    int64_t pts;
+
+    FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
 
-    if ((fm->eof & eof_mask) == eof_mask) // flush done?
-        return AVERROR_EOF;
-    if ((ret = request_inlink(ctx, INPUT_MAIN)) < 0)
+    if ((fm->got_frame[INPUT_MAIN] == 0) &&
+        (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_MAIN], &frame)) > 0) {
+        ret = filter_frame(ctx->inputs[INPUT_MAIN], frame);
+        if (ret < 0)
+            return ret;
+    }
+    if (ret < 0)
         return ret;
-    if (fm->ppsrc && (ret = request_inlink(ctx, INPUT_CLEANSRC)) < 0)
+    if (fm->ppsrc &&
+        (fm->got_frame[INPUT_CLEANSRC] == 0) &&
+        (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_CLEANSRC], &frame)) > 0) {
+        ret = filter_frame(ctx->inputs[INPUT_CLEANSRC], frame);
+        if (ret < 0)
+            return ret;
+    }
+    if (ret < 0) {
         return ret;
-    return 0;
+    } else if (ff_inlink_acknowledge_status(ctx->inputs[INPUT_MAIN], &status, &pts)) {
+        if (status == AVERROR_EOF) { // flushing
+            fm->eof |= 1 << INPUT_MAIN;
+            ret = filter_frame(ctx->inputs[INPUT_MAIN], NULL);
+        }
+        ff_outlink_set_status(ctx->outputs[0], status, pts);
+        return ret;
+    } else if (fm->ppsrc && ff_inlink_acknowledge_status(ctx->inputs[INPUT_CLEANSRC], &status, &pts)) {
+        if (status == AVERROR_EOF) { // flushing
+            fm->eof |= 1 << INPUT_CLEANSRC;
+            ret = filter_frame(ctx->inputs[INPUT_CLEANSRC], NULL);
+        }
+        ff_outlink_set_status(ctx->outputs[0], status, pts);
+        return ret;
+    } else {
+        if (ff_outlink_frame_wanted(ctx->outputs[0])) {
+            if (fm->got_frame[INPUT_MAIN] == 0)
+                ff_inlink_request_frame(ctx->inputs[INPUT_MAIN]);
+            if (fm->ppsrc && (fm->got_frame[INPUT_CLEANSRC] == 0))
+                ff_inlink_request_frame(ctx->inputs[INPUT_CLEANSRC]);
+        }
+        return 0;
+    }
 }
 
 static int query_formats(AVFilterContext *ctx)
 {
-    // TODO: second input source can support >8bit depth
+    FieldMatchContext *fm = ctx->priv;
+
     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_NONE
     };
+    static const enum AVPixelFormat unproc_pix_fmts[] = {
+        AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
+        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
+        AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
+        AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
+        AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
+        AV_PIX_FMT_YUVJ411P,
+        AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
+        AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
+        AV_PIX_FMT_YUV440P10,
+        AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
+        AV_PIX_FMT_YUV440P12,
+        AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
+        AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
+        AV_PIX_FMT_NONE
+    };
+    int ret;
+
     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
     if (!fmts_list)
         return AVERROR(ENOMEM);
-    return ff_set_common_formats(ctx, fmts_list);
+    if (!fm->ppsrc) {
+        return ff_set_common_formats(ctx, fmts_list);
+    }
+
+    if ((ret = ff_formats_ref(fmts_list, &ctx->inputs[INPUT_MAIN]->out_formats)) < 0)
+        return ret;
+    fmts_list = ff_make_format_list(unproc_pix_fmts);
+    if (!fmts_list)
+        return AVERROR(ENOMEM);
+    if ((ret = ff_formats_ref(fmts_list, &ctx->outputs[0]->in_formats)) < 0)
+        return ret;
+    if ((ret = ff_formats_ref(fmts_list, &ctx->inputs[INPUT_CLEANSRC]->out_formats)) < 0)
+        return ret;
+    return 0;
 }
 
 static int config_input(AVFilterLink *inlink)
@@ -885,7 +950,7 @@ static int config_input(AVFilterLink *inlink)
     fm->tpitchy  = FFALIGN(w,      16);
     fm->tpitchuv = FFALIGN(w >> 1, 16);
 
-    fm->tbuffer = av_malloc(h/2 * fm->tpitchy);
+    fm->tbuffer = av_calloc((h/2 + 4) * fm->tpitchy, sizeof(*fm->tbuffer));
     fm->c_array = av_malloc((((w + fm->blockx/2)/fm->blockx)+1) *
                             (((h + fm->blocky/2)/fm->blocky)+1) *
                             4 * sizeof(*fm->c_array));
@@ -901,7 +966,6 @@ static av_cold int fieldmatch_init(AVFilterContext *ctx)
     AVFilterPad pad = {
         .name         = av_strdup("main"),
         .type         = AVMEDIA_TYPE_VIDEO,
-        .filter_frame = filter_frame,
         .config_props = config_input,
     };
     int ret;
@@ -947,7 +1011,12 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx)
         av_frame_free(&fm->prv);
     if (fm->nxt != fm->src)
         av_frame_free(&fm->nxt);
+    if (fm->prv2 != fm->src2)
+        av_frame_free(&fm->prv2);
+    if (fm->nxt2 != fm->src2)
+        av_frame_free(&fm->nxt2);
     av_frame_free(&fm->src);
+    av_frame_free(&fm->src2);
     av_freep(&fm->map_data[0]);
     av_freep(&fm->cmask_data[0]);
     av_freep(&fm->tbuffer);
@@ -959,10 +1028,12 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx)
 static int config_output(AVFilterLink *outlink)
 {
     AVFilterContext *ctx  = outlink->src;
-    const FieldMatchContext *fm = ctx->priv;
+    FieldMatchContext *fm = ctx->priv;
     const AVFilterLink *inlink =
         ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN];
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
 
+    fm->bpc = (desc->comp[0].depth + 7) / 8;
     outlink->time_base = inlink->time_base;
     outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
     outlink->frame_rate = inlink->frame_rate;
@@ -975,7 +1046,6 @@ static const AVFilterPad fieldmatch_outputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
-        .request_frame = request_frame,
         .config_props  = config_output,
     },
     { NULL }
@@ -987,6 +1057,7 @@ AVFilter ff_vf_fieldmatch = {
     .query_formats  = query_formats,
     .priv_size      = sizeof(FieldMatchContext),
     .init           = fieldmatch_init,
+    .activate       = activate,
     .uninit         = fieldmatch_uninit,
     .inputs         = NULL,
     .outputs        = fieldmatch_outputs,