[FFmpeg-devel] [PATCH 05/25] avfilter/buffersrc: add color_space/range parameters

Niklas Haas ffmpeg at haasn.xyz
Thu Nov 9 14:19:37 EET 2023


From: Niklas Haas <git at haasn.dev>

To allow adding proper negotiation, in particular, to fftools.

These values will simply be negotiated downstream for YUV formats, and
ignored otherwise.
---
 doc/filters.texi        | 10 +++++++
 libavfilter/buffersrc.c | 62 ++++++++++++++++++++++++++++++++++++-----
 libavfilter/buffersrc.h |  6 ++++
 3 files changed, 71 insertions(+), 7 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 12113d7802..55a333680c 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -27939,6 +27939,16 @@ Specify the timebase assumed by the timestamps of the buffered frames.
 @item frame_rate
 Specify the frame rate expected for the video stream.
 
+ at item colorspace
+A string representing the color space of the buffered video frames.
+It may be a number corresponding to a color space, or a color space
+name.
+
+ at item range
+A string representing the color range of the buffered video frames.
+It may be a number corresponding to a color range, or a color range
+name.
+
 @item pixel_aspect, sar
 The sample (pixel) aspect ratio of the input video.
 
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 453fc0fd5c..76f3f1d7a5 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -49,6 +49,8 @@ typedef struct BufferSourceContext {
     /* video only */
     int               w, h;
     enum AVPixelFormat  pix_fmt;
+    enum AVColorSpace color_space;
+    enum AVColorRange color_range;
     AVRational        pixel_aspect;
 
     AVBufferRef *hw_frames_ctx;
@@ -64,10 +66,13 @@ typedef struct BufferSourceContext {
     int64_t last_pts;
 } BufferSourceContext;
 
-#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format, pts)\
-    if (c->w != width || c->h != height || c->pix_fmt != format) {\
-        av_log(s, AV_LOG_INFO, "filter context - w: %d h: %d fmt: %d, incoming frame - w: %d h: %d fmt: %d pts_time: %s\n",\
-               c->w, c->h, c->pix_fmt, width, height, format, av_ts2timestr(pts, &s->outputs[0]->time_base));\
+#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format, csp, range, pts)\
+    if (c->w != width || c->h != height || c->pix_fmt != format ||\
+        c->color_space != csp || c->color_range != range) {\
+        av_log(s, AV_LOG_INFO, "filter context - w: %d h: %d fmt: %d csp: %s range: %s, incoming frame - w: %d h: %d fmt: %d csp: %s range: %s pts_time: %s\n",\
+               c->w, c->h, c->pix_fmt, av_color_space_name(c->color_space), av_color_range_name(c->color_range),\
+               width, height, format, av_color_space_name(csp), av_color_range_name(range),\
+               av_ts2timestr(pts, &s->outputs[0]->time_base));\
         av_log(s, AV_LOG_WARNING, "Changing video frame properties on the fly is not supported by all filters.\n");\
     }
 
@@ -88,6 +93,8 @@ AVBufferSrcParameters *av_buffersrc_parameters_alloc(void)
         return NULL;
 
     par->format = -1;
+    par->color_range = AVCOL_RANGE_UNSPECIFIED;
+    par->color_space = AVCOL_SPC_UNSPECIFIED;
 
     return par;
 }
@@ -118,6 +125,10 @@ int av_buffersrc_parameters_set(AVFilterContext *ctx, AVBufferSrcParameters *par
             if (!s->hw_frames_ctx)
                 return AVERROR(ENOMEM);
         }
+        if (param->color_space != AVCOL_SPC_UNSPECIFIED)
+            s->color_space = param->color_space;
+        if (param->color_range != AVCOL_RANGE_UNSPECIFIED)
+            s->color_range = param->color_range;
         break;
     case AVMEDIA_TYPE_AUDIO:
         if (param->format != AV_SAMPLE_FMT_NONE) {
@@ -205,7 +216,8 @@ FF_ENABLE_DEPRECATION_WARNINGS
         switch (ctx->outputs[0]->type) {
         case AVMEDIA_TYPE_VIDEO:
             CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height,
-                                     frame->format, frame->pts);
+                                     frame->format, frame->colorspace,
+                                     frame->color_range, frame->pts);
             break;
         case AVMEDIA_TYPE_AUDIO:
             /* For layouts unknown on input but known on link after negotiation. */
@@ -302,10 +314,11 @@ static av_cold int init_video(AVFilterContext *ctx)
         return AVERROR(EINVAL);
     }
 
-    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d\n",
+    av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d pixfmt:%s tb:%d/%d fr:%d/%d sar:%d/%d csp:%s range:%s\n",
            c->w, c->h, av_get_pix_fmt_name(c->pix_fmt),
            c->time_base.num, c->time_base.den, c->frame_rate.num, c->frame_rate.den,
-           c->pixel_aspect.num, c->pixel_aspect.den);
+           c->pixel_aspect.num, c->pixel_aspect.den,
+           av_color_space_name(c->color_space), av_color_range_name(c->color_range));
 
     return 0;
 }
@@ -328,6 +341,30 @@ static const AVOption buffer_options[] = {
     { "pixel_aspect",  "sample aspect ratio",    OFFSET(pixel_aspect),     AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V },
     { "time_base",     NULL,                     OFFSET(time_base),        AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V },
     { "frame_rate",    NULL,                     OFFSET(frame_rate),       AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V },
+    { "colorspace", "select colorspace", OFFSET(color_space), AV_OPT_TYPE_INT, {.i64=AVCOL_SPC_UNSPECIFIED}, 0, AVCOL_SPC_NB-1, V, "colorspace"},
+    {   "gbr",         NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_RGB},               INT_MIN, INT_MAX, V, "colorspace"},
+    {   "bt709",       NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709},             INT_MIN, INT_MAX, V, "colorspace"},
+    {   "unknown",     NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_UNSPECIFIED},       INT_MIN, INT_MAX, V, "colorspace"},
+    {   "fcc",         NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_FCC},               INT_MIN, INT_MAX, V, "colorspace"},
+    {   "bt470bg",     NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG},           INT_MIN, INT_MAX, V, "colorspace"},
+    {   "smpte170m",   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M},         INT_MIN, INT_MAX, V, "colorspace"},
+    {   "smpte240m",   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M},         INT_MIN, INT_MAX, V, "colorspace"},
+    {   "ycgco",       NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO},             INT_MIN, INT_MAX, V, "colorspace"},
+    {   "bt2020nc",    NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL},        INT_MIN, INT_MAX, V, "colorspace"},
+    {   "bt2020c",     NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL},         INT_MIN, INT_MAX, V, "colorspace"},
+    {   "smpte2085",   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE2085},         INT_MIN, INT_MAX, V, "colorspace"},
+    {   "chroma-derived-nc",  NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_NCL},INT_MIN, INT_MAX, V, "colorspace"},
+    {   "chroma-derived-c",   NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_CL}, INT_MIN, INT_MAX, V, "colorspace"},
+    {   "ictcp",       NULL,  0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP},             INT_MIN, INT_MAX, V, "colorspace"},
+    { "range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, AVCOL_RANGE_NB-1, V, "range"},
+    {   "unspecified", NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED},  0, 0, V, "range"},
+    {   "unknown",     NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED},  0, 0, V, "range"},
+    {   "limited",     NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},         0, 0, V, "range"},
+    {   "tv",          NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},         0, 0, V, "range"},
+    {   "mpeg",        NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},         0, 0, V, "range"},
+    {   "full",        NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},         0, 0, V, "range"},
+    {   "pc",          NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},         0, 0, V, "range"},
+    {   "jpeg",        NULL,   0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},         0, 0, V, "range"},
     { NULL },
 };
 
@@ -425,6 +462,8 @@ static int query_formats(AVFilterContext *ctx)
     AVFilterChannelLayouts *channel_layouts = NULL;
     AVFilterFormats *formats = NULL;
     AVFilterFormats *samplerates = NULL;
+    AVFilterFormats *color_spaces = NULL;
+    AVFilterFormats *color_ranges = NULL;
     int ret;
 
     switch (ctx->outputs[0]->type) {
@@ -432,6 +471,15 @@ static int query_formats(AVFilterContext *ctx)
         if ((ret = ff_add_format         (&formats, c->pix_fmt)) < 0 ||
             (ret = ff_set_common_formats (ctx     , formats   )) < 0)
             return ret;
+        /* force specific colorspace/range downstream only for ordinary YUV */
+        if (ff_fmt_is_regular_yuv(c->pix_fmt)) {
+            if ((ret = ff_add_format(&color_spaces, c->color_space)) < 0 ||
+                (ret = ff_set_common_color_spaces(ctx, color_spaces)) < 0)
+                return ret;
+            if ((ret = ff_add_format(&color_ranges, c->color_range)) < 0 ||
+                (ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
+                return ret;
+        }
         break;
     case AVMEDIA_TYPE_AUDIO:
         if ((ret = ff_add_format             (&formats    , c->sample_fmt )) < 0 ||
diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h
index 3b248b37cd..4357a7bbfb 100644
--- a/libavfilter/buffersrc.h
+++ b/libavfilter/buffersrc.h
@@ -105,6 +105,12 @@ typedef struct AVBufferSrcParameters {
      */
     AVBufferRef *hw_frames_ctx;
 
+    /**
+     * Video only, the YUV colorspace and range
+     */
+    enum AVColorSpace color_space;
+    enum AVColorRange color_range;
+
     /**
      * Audio only, the audio sampling rate in samples per second.
      */
-- 
2.42.0



More information about the ffmpeg-devel mailing list