]> git.sesse.net Git - ffmpeg/blobdiff - libavfilter/vf_tonemap.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / vf_tonemap.c
index 10fd7ea0165b33d0bcdbe601fffa127733dd2c29..4d04118eac33b82f5be9b85a910372305ed15c92 100644 (file)
 #include "libavutil/imgutils.h"
 #include "libavutil/internal.h"
 #include "libavutil/intreadwrite.h"
-#include "libavutil/mastering_display_metadata.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
 
 #include "avfilter.h"
+#include "colorspace.h"
 #include "formats.h"
 #include "internal.h"
 #include "video.h"
 
-#define REFERENCE_WHITE 100.0f
-
 enum TonemapAlgorithm {
     TONEMAP_NONE,
     TONEMAP_LINEAR,
@@ -52,11 +50,6 @@ enum TonemapAlgorithm {
     TONEMAP_MAX,
 };
 
-typedef struct LumaCoefficients {
-    double cr, cg, cb;
-} LumaCoefficients;
-
-
 static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = {
     [AVCOL_SPC_FCC]        = { 0.30,   0.59,   0.11   },
     [AVCOL_SPC_BT470BG]    = { 0.299,  0.587,  0.114  },
@@ -75,7 +68,7 @@ typedef struct TonemapContext {
     double desat;
     double peak;
 
-    const LumaCoefficients *coeffs;
+    const struct LumaCoefficients *coeffs;
 } TonemapContext;
 
 static const enum AVPixelFormat pix_fmts[] = {
@@ -114,31 +107,6 @@ static av_cold int init(AVFilterContext *ctx)
     return 0;
 }
 
-static double determine_signal_peak(AVFrame *in)
-{
-    AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL);
-    double peak = 0;
-
-    if (sd) {
-        AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data;
-        peak = clm->MaxCLL / REFERENCE_WHITE;
-    }
-
-    sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);
-    if (!peak && sd) {
-        AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data;
-        if (metadata->has_luminance)
-            peak = av_q2d(metadata->max_luminance) / REFERENCE_WHITE;
-    }
-
-    // For untagged source, use peak of 10000 if SMPTE ST.2084
-    // otherwise assume HLG with reference display peak 1000.
-    if (!peak)
-        peak = in->color_trc == AVCOL_TRC_SMPTE2084 ? 100.0f : 10.0f;
-
-    return peak;
-}
-
 static float hable(float in)
 {
     float a = 0.15f, b = 0.50f, c = 0.10f, d = 0.20f, e = 0.02f, f = 0.30f;
@@ -223,10 +191,36 @@ static void tonemap(TonemapContext *s, AVFrame *out, const AVFrame *in,
     *b_out *= sig / sig_orig;
 }
 
+typedef struct ThreadData {
+    AVFrame *in, *out;
+    const AVPixFmtDescriptor *desc;
+    double peak;
+} ThreadData;
+
+static int tonemap_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
+{
+    TonemapContext *s = ctx->priv;
+    ThreadData *td = arg;
+    AVFrame *in = td->in;
+    AVFrame *out = td->out;
+    const AVPixFmtDescriptor *desc = td->desc;
+    const int slice_start = (in->height * jobnr) / nb_jobs;
+    const int slice_end = (in->height * (jobnr+1)) / nb_jobs;
+    double peak = td->peak;
+
+    for (int y = slice_start; y < slice_end; y++)
+        for (int x = 0; x < out->width; x++)
+            tonemap(s, out, in, desc, x, y, peak);
+
+    return 0;
+}
+
 static int filter_frame(AVFilterLink *link, AVFrame *in)
 {
-    TonemapContext *s = link->dst->priv;
-    AVFilterLink *outlink = link->dst->outputs[0];
+    AVFilterContext *ctx = link->dst;
+    TonemapContext *s = ctx->priv;
+    AVFilterLink *outlink = ctx->outputs[0];
+    ThreadData td;
     AVFrame *out;
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
     const AVPixFmtDescriptor *odesc = av_pix_fmt_desc_get(outlink->format);
@@ -260,7 +254,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
 
     /* read peak from side data if not passed in */
     if (!peak) {
-        peak = determine_signal_peak(in);
+        peak = ff_determine_signal_peak(in);
         av_log(s, AV_LOG_DEBUG, "Computed signal peak: %f\n", peak);
     }
 
@@ -277,9 +271,11 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
     }
 
     /* do the tone map */
-    for (y = 0; y < out->height; y++)
-        for (x = 0; x < out->width; x++)
-            tonemap(s, out, in, desc, x, y, peak);
+    td.out = out;
+    td.in = in;
+    td.desc = desc;
+    td.peak = peak;
+    ctx->internal->execute(ctx, tonemap_slice, &td, NULL, FFMIN(in->height, ff_filter_get_nb_threads(ctx)));
 
     /* copy/generate alpha if needed */
     if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) {
@@ -297,6 +293,8 @@ static int filter_frame(AVFilterLink *link, AVFrame *in)
 
     av_frame_free(&in);
 
+    ff_update_hdr_metadata(out, peak);
+
     return ff_filter_frame(outlink, out);
 }
 
@@ -317,13 +315,7 @@ static const AVOption tonemap_options[] = {
     { NULL }
 };
 
-static const AVClass tonemap_class = {
-    .class_name       = "tonemap",
-    .item_name        = av_default_item_name,
-    .option           = tonemap_options,
-    .version          = LIBAVUTIL_VERSION_INT,
-    .category         = AV_CLASS_CATEGORY_FILTER,
-};
+AVFILTER_DEFINE_CLASS(tonemap);
 
 static const AVFilterPad tonemap_inputs[] = {
     {
@@ -342,7 +334,7 @@ static const AVFilterPad tonemap_outputs[] = {
     { NULL }
 };
 
-AVFilter ff_vf_tonemap = {
+const AVFilter ff_vf_tonemap = {
     .name            = "tonemap",
     .description     = NULL_IF_CONFIG_SMALL("Conversion to/from different dynamic ranges."),
     .init            = init,
@@ -351,4 +343,5 @@ AVFilter ff_vf_tonemap = {
     .priv_class      = &tonemap_class,
     .inputs          = tonemap_inputs,
     .outputs         = tonemap_outputs,
+    .flags           = AVFILTER_FLAG_SLICE_THREADS,
 };