[FFmpeg-devel] [PATCH 4/7] fftools/ffmpeg_filter: auto-insert zscale filter

Niklas Haas ffmpeg at haasn.xyz
Wed Oct 11 17:55:38 EEST 2023


From: Niklas Haas <git at haasn.dev>

Since swscale currently can't handle conversion between different
colorimetry sets, supplement the missing bits and pieces using zscale.
Subject to change in the future, if libswscale ever gets the capability
to convert between colorspaces natively.
---
 fftools/ffmpeg_filter.c | 62 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index c1bedfda00..c60b9d99f7 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -20,6 +20,8 @@
 
 #include <stdint.h>
 
+#include "config_components.h"
+
 #include "ffmpeg.h"
 
 #include "libavfilter/avfilter.h"
@@ -171,6 +173,9 @@ typedef struct OutputFilterPriv {
     AVChannelLayout ch_layout;
     enum AVColorSpace csp;
     enum AVColorRange color_range;
+    enum AVChromaLocation chroma_loc;
+    enum AVColorPrimaries prim;
+    enum AVColorTransferCharacteristic trc;
 
     // time base in which the output is sent to our downstream
     // does not need to match the filtersink's timebase
@@ -188,6 +193,9 @@ typedef struct OutputFilterPriv {
     const int *sample_rates;
     const enum AVColorSpace *csps;
     const enum AVColorRange *color_ranges;
+    const enum AVChromaLocation *chroma_locs;
+    const enum AVColorPrimaries *prims;
+    const enum AVColorTransferCharacteristic *trcs;
 
     AVRational enc_timebase;
     // offset for output timestamps, in AV_TIME_BASE_Q
@@ -378,6 +386,17 @@ DEF_CHOOSE_FORMAT(out_color_matrix, enum AVColorSpace, csp, csps,
 DEF_CHOOSE_FORMAT(out_range, enum AVColorRange, color_range, color_ranges,
                   AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name);
 
+#if CONFIG_ZSCALE_FILTER
+DEF_CHOOSE_FORMAT(chromal, enum AVChromaLocation, chroma_loc, chroma_locs,
+                  AVCHROMA_LOC_UNSPECIFIED, "%s", av_chroma_location_name);
+
+DEF_CHOOSE_FORMAT(primaries, enum AVColorPrimaries, prim, prims,
+                  AVCOL_PRI_UNSPECIFIED, "%s", av_color_primaries_name);
+
+DEF_CHOOSE_FORMAT(transfer, enum AVColorTransferCharacteristic, trc, trcs,
+                  AVCOL_TRC_UNSPECIFIED, "%s", av_color_transfer_name);
+#endif
+
 static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint)
 {
     if (av_channel_layout_check(&ofp->ch_layout)) {
@@ -724,6 +743,21 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost)
                     ofp->color_ranges = mjpeg_ranges;
             }
         }
+        if (ost->enc_ctx->chroma_sample_location) {
+            ofp->chroma_loc = ost->enc_ctx->chroma_sample_location;
+        } else {
+            ofp->chroma_locs = c->chroma_locs;
+        }
+        if (ost->enc_ctx->color_primaries) {
+            ofp->prim = ost->enc_ctx->color_primaries;
+        } else {
+            ofp->prims = c->primaries;
+        }
+        if (ost->enc_ctx->color_trc) {
+            ofp->trc = ost->enc_ctx->color_trc;
+        } else {
+            ofp->trcs = c->trcs;
+        }
         if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
             ofp->format = ost->enc_ctx->pix_fmt;
         } else {
@@ -1280,6 +1314,34 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter,
             last_filter = filter;
             pad_idx = 0;
         }
+
+#if CONFIG_ZSCALE_FILTER
+        av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED);
+        choose_chromal(ofp,   &bprint);
+        choose_primaries(ofp, &bprint);
+        choose_transfer(ofp,  &bprint);
+        if (bprint.len) {
+            /* Colorspace format conversion needed */
+            AVFilterContext *filter;
+
+            if (!av_bprint_is_complete(&bprint))
+                return AVERROR(ENOMEM);
+
+            snprintf(name, sizeof(name), "color_out_%d_%d",
+                     ost->file_index, ost->index);
+            ret = avfilter_graph_create_filter(&filter,
+                                               avfilter_get_by_name("zscale"),
+                                               name, bprint.str, NULL, fg->graph);
+            av_bprint_finalize(&bprint, NULL);
+            if (ret < 0)
+                return ret;
+            if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0)
+                return ret;
+
+            last_filter = filter;
+            pad_idx = 0;
+        }
+#endif
     }
 
     snprintf(name, sizeof(name), "trim_out_%d_%d",
-- 
2.42.0



More information about the ffmpeg-devel mailing list