[FFmpeg-devel] [PATCH 07/25] avfilter: negotiate color_range between filters
Paul B Mahol
onemda at gmail.com
Sat Dec 16 12:12:27 EET 2017
Signed-off-by: Paul B Mahol <onemda at gmail.com>
---
fftools/ffmpeg.c | 2 ++
fftools/ffmpeg.h | 1 +
fftools/ffmpeg_filter.c | 57 +++++++++++++++++++++++++++++++---
fftools/ffmpeg_opt.c | 2 ++
libavcodec/utils.c | 11 +++++++
libavfilter/avfilter.c | 9 ++++--
libavfilter/avfilter.h | 4 ++-
libavfilter/avfiltergraph.c | 53 ++++++++++++++++++++++++++++++++
libavfilter/buffersink.c | 16 ++++++++++
libavfilter/buffersink.h | 1 +
libavfilter/buffersrc.c | 4 +++
libavfilter/formats.c | 75 ++++++++++++++++++++++++++++++++++++++++++---
libavfilter/formats.h | 31 +++++++++++++++++++
libavfilter/internal.h | 11 +++++++
libavfilter/vf_format.c | 46 ++++++++++++++++++++++++++-
libavfilter/vf_noise.c | 6 +++-
libavfilter/vf_scale.c | 17 ++++++++--
libavfilter/vsrc_testsrc.c | 15 +++++++--
tests/fate/filter-video.mak | 2 +-
tests/fate/pixlet.mak | 2 +-
20 files changed, 343 insertions(+), 22 deletions(-)
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 6aff3366c5..64de55d9a5 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -3390,6 +3390,8 @@ static int init_output_stream_encode(OutputStream *ost)
enc_ctx->bits_per_raw_sample = FFMIN(dec_ctx->bits_per_raw_sample,
av_pix_fmt_desc_get(enc_ctx->pix_fmt)->comp[0].depth);
+ enc_ctx->color_range = av_buffersink_get_color_range(ost->filter->filter);
+
enc_ctx->framerate = ost->frame_rate;
ost->st->avg_frame_rate = ost->frame_rate;
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 4e73d59082..071f3651f8 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -271,6 +271,7 @@ typedef struct OutputFilter {
/* desired output stream properties */
int width, height;
+ enum AVColorRange color_range;
AVRational frame_rate;
int format;
int sample_rate;
diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c
index 877fd670e6..16ad79625b 100644
--- a/fftools/ffmpeg_filter.c
+++ b/fftools/ffmpeg_filter.c
@@ -89,6 +89,28 @@ enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCod
return target;
}
+static enum AVColorRange choose_color_range(AVStream *st, AVCodecContext *enc_ctx, AVCodec *codec, enum AVColorRange target)
+{
+ if (codec && codec->color_ranges) {
+ const enum AVColorRange *p = codec->color_ranges;
+
+ for (; *p != AVCOL_RANGE_UNSPECIFIED; p++) {
+ if (*p == target)
+ break;
+ }
+ if (*p == AVCOL_RANGE_UNSPECIFIED) {
+ if (target != AVCOL_RANGE_UNSPECIFIED)
+ av_log(NULL, AV_LOG_WARNING,
+ "Incompatible color range '%s' for codec '%s', auto-selecting color range '%s'\n",
+ av_color_range_name(target),
+ codec->name,
+ av_color_range_name(codec->color_ranges[0]));
+ return codec->color_ranges[0];
+ }
+ }
+ return target;
+}
+
void choose_sample_fmt(AVStream *st, AVCodec *codec)
{
if (codec && codec->sample_fmts) {
@@ -127,7 +149,19 @@ static char *choose_pix_fmts(OutputFilter *ofilter)
return av_strdup(av_get_pix_fmt_name(ost->enc_ctx->pix_fmt));
}
if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
- return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt)));
+ AVIOContext *s = NULL;
+ uint8_t *ret;
+ int len;
+
+ if (avio_open_dyn_buf(&s) < 0)
+ exit_program(1);
+
+ avio_printf(s, "%s:%s", av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->pix_fmt)),
+ av_color_range_name(choose_color_range(ost->st, ost->enc_ctx, ost->enc, ost->enc_ctx->color_range)));
+
+ len = avio_close_dyn_buf(s, &ret);
+ ret[len] = 0;
+ return ret;
} else if (ost->enc && ost->enc->pix_fmts) {
const enum AVPixelFormat *p;
AVIOContext *s = NULL;
@@ -144,7 +178,20 @@ static char *choose_pix_fmts(OutputFilter *ofilter)
for (; *p != AV_PIX_FMT_NONE; p++) {
const char *name = av_get_pix_fmt_name(*p);
- avio_printf(s, "%s|", name);
+ avio_printf(s, "%s", name);
+ if (*(p + 1) != AV_PIX_FMT_NONE)
+ avio_printf(s, "|");
+ else
+ avio_printf(s, ":");
+ }
+
+ if (ost->enc->color_ranges) {
+ const enum AVColorRange *c = ost->enc->color_ranges;
+
+ for (; *c != AVCOL_RANGE_UNSPECIFIED; c++) {
+ const char *name = av_color_range_name(*c);
+ avio_printf(s, "%s|", name);
+ }
}
len = avio_close_dyn_buf(s, &ret);
ret[len - 1] = 0;
@@ -777,10 +824,11 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter,
av_bprint_init(&args, 0, 1);
av_bprintf(&args,
"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:"
- "pixel_aspect=%d/%d:sws_param=flags=%d",
+ "pixel_aspect=%d/%d:sws_param=flags=%d:color_range=%s",
ifilter->width, ifilter->height, ifilter->format,
tb.num, tb.den, sar.num, sar.den,
- SWS_BILINEAR + ((ist->dec_ctx->flags&AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0));
+ SWS_BILINEAR + ((ist->dec_ctx->flags&AV_CODEC_FLAG_BITEXACT) ? SWS_BITEXACT:0),
+ av_color_range_name(ist->dec_ctx->color_range));
if (fr.num && fr.den)
av_bprintf(&args, ":frame_rate=%d/%d", fr.num, fr.den);
snprintf(name, sizeof(name), "graph %d input from stream %d:%d", fg->index,
@@ -1110,6 +1158,7 @@ int configure_filtergraph(FilterGraph *fg)
ofilter->width = av_buffersink_get_w(sink);
ofilter->height = av_buffersink_get_h(sink);
+ ofilter->color_range = av_buffersink_get_color_range(sink);
ofilter->sample_rate = av_buffersink_get_sample_rate(sink);
ofilter->channel_layout = av_buffersink_get_channel_layout(sink);
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index a6e36ac822..f5156c0efc 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -2506,6 +2506,8 @@ loop_end:
f->frame_rate = ost->frame_rate;
f->width = ost->enc_ctx->width;
f->height = ost->enc_ctx->height;
+ if (ost->enc_ctx->color_range != AVCOL_RANGE_UNSPECIFIED)
+ f->color_range = ost->enc_ctx->color_range;
if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) {
f->format = ost->enc_ctx->pix_fmt;
} else if (ost->enc->pix_fmts) {
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 873f39f9bd..3eca490a33 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -879,6 +879,17 @@ FF_ENABLE_DEPRECATION_WARNINGS
avctx->codec->pix_fmts[i] == AV_PIX_FMT_YUVJ444P)
avctx->color_range = AVCOL_RANGE_JPEG;
}
+ if (avctx->codec->color_ranges) {
+ for (i = 0; avctx->codec->color_ranges[i] != AVCOL_RANGE_UNSPECIFIED; i++)
+ if (avctx->color_range == avctx->codec->color_ranges[i])
+ break;
+ if (avctx->codec->color_ranges[i] == AVCOL_RANGE_UNSPECIFIED) {
+ av_log(avctx, AV_LOG_ERROR, "Specified color range %s is invalid or not supported\n",
+ (char *)av_x_if_null(av_color_range_name(avctx->color_range), "unknown"));
+ ret = AVERROR(EINVAL);
+ goto free_and_end;
+ }
+ }
if (avctx->codec->supported_samplerates) {
for (i = 0; avctx->codec->supported_samplerates[i] != 0; i++)
if (avctx->sample_rate == avctx->codec->supported_samplerates[i])
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 4a579bb49d..c3a19d100c 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -262,6 +262,9 @@ int avfilter_insert_filter(AVFilterLink *link, AVFilterContext *filt,
if (link->out_formats)
ff_formats_changeref(&link->out_formats,
&filt->outputs[filt_dstpad_idx]->out_formats);
+ if (link->out_color_ranges)
+ ff_formats_changeref(&link->out_color_ranges,
+ &filt->outputs[filt_dstpad_idx]->out_color_ranges);
if (link->out_samplerates)
ff_formats_changeref(&link->out_samplerates,
&filt->outputs[filt_dstpad_idx]->out_samplerates);
@@ -785,6 +788,8 @@ static void free_link(AVFilterLink *link)
ff_formats_unref(&link->in_formats);
ff_formats_unref(&link->out_formats);
+ ff_formats_unref(&link->in_color_ranges);
+ ff_formats_unref(&link->out_color_ranges);
ff_formats_unref(&link->in_samplerates);
ff_formats_unref(&link->out_samplerates);
ff_channel_layouts_unref(&link->in_channel_layouts);
@@ -970,9 +975,7 @@ int avfilter_init_str(AVFilterContext *filter, const char *args)
}
#if FF_API_OLD_FILTER_OPTS_ERROR
- if ( !strcmp(filter->filter->name, "format") ||
- !strcmp(filter->filter->name, "noformat") ||
- !strcmp(filter->filter->name, "frei0r") ||
+ if ( !strcmp(filter->filter->name, "frei0r") ||
!strcmp(filter->filter->name, "frei0r_src") ||
!strcmp(filter->filter->name, "ocv") ||
!strcmp(filter->filter->name, "pan") ||
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 40ad28ffd8..138bdeb5c9 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -456,7 +456,7 @@ struct AVFilterLink {
*****************************************************************
*/
/**
- * Lists of formats and channel layouts supported by the input and output
+ * Lists of formats, color_ranges and channel layouts supported by the input and output
* filters respectively. These lists are used for negotiating the format
* to actually be used, which will be loaded into the format and
* channel_layout members, above, when chosen.
@@ -464,6 +464,8 @@ struct AVFilterLink {
*/
AVFilterFormats *in_formats;
AVFilterFormats *out_formats;
+ AVFilterFormats *in_color_ranges;
+ AVFilterFormats *out_color_ranges;
/**
* Lists of channel layouts and sample rates used for automatic
diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c
index 4cc6892404..0d023a5881 100644
--- a/libavfilter/avfiltergraph.c
+++ b/libavfilter/avfiltergraph.c
@@ -317,6 +317,7 @@ static int filter_query_formats(AVFilterContext *ctx)
{
int ret, i;
AVFilterFormats *formats;
+ AVFilterFormats *color_ranges;
AVFilterChannelLayouts *chlayouts;
AVFilterFormats *samplerates;
enum AVMediaType type = ctx->inputs && ctx->inputs [0] ? ctx->inputs [0]->type :
@@ -338,6 +339,11 @@ static int filter_query_formats(AVFilterContext *ctx)
formats = ff_all_formats(type);
if ((ret = ff_set_common_formats(ctx, formats)) < 0)
return ret;
+ if (type == AVMEDIA_TYPE_VIDEO) {
+ color_ranges = ff_all_color_ranges();
+ if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
+ return ret;
+ }
if (type == AVMEDIA_TYPE_AUDIO) {
samplerates = ff_all_samplerates();
if ((ret = ff_set_common_samplerates(ctx, samplerates)) < 0)
@@ -360,6 +366,9 @@ static int formats_declared(AVFilterContext *f)
!(f->inputs[i]->out_samplerates &&
f->inputs[i]->out_channel_layouts))
return 0;
+ if (f->inputs[i]->type == AVMEDIA_TYPE_VIDEO &&
+ !(f->inputs[i]->out_color_ranges))
+ return 0;
}
for (i = 0; i < f->nb_outputs; i++) {
if (!f->outputs[i]->in_formats)
@@ -368,6 +377,9 @@ static int formats_declared(AVFilterContext *f)
!(f->outputs[i]->in_samplerates &&
f->outputs[i]->in_channel_layouts))
return 0;
+ if (f->outputs[i]->type == AVMEDIA_TYPE_VIDEO &&
+ !(f->outputs[i]->in_color_ranges))
+ return 0;
}
return 1;
}
@@ -485,6 +497,15 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
convert_needed = 1;
}
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ if (link->in_color_ranges != link->out_color_ranges
+ && link->in_color_ranges && link->out_color_ranges)
+ if (!can_merge_formats(link->in_color_ranges,
+ link->out_color_ranges,
+ 0, 1))
+ convert_needed = 1;
+ }
+
#define MERGE_DISPATCH(field, statement) \
if (!(link->in_ ## field && link->out_ ## field)) { \
count_delayed++; \
@@ -507,6 +528,13 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
convert_needed = 1;
)
}
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ MERGE_DISPATCH(color_ranges,
+ if (!ff_merge_samplerates(link->in_color_ranges,
+ link->out_color_ranges))
+ convert_needed = 1;
+ )
+ }
MERGE_DISPATCH(formats,
if (!ff_merge_formats(link->in_formats, link->out_formats,
link->type))
@@ -575,6 +603,12 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
av_assert0( inlink->out_formats->refcount > 0);
av_assert0(outlink-> in_formats->refcount > 0);
av_assert0(outlink->out_formats->refcount > 0);
+ if (outlink->type == AVMEDIA_TYPE_VIDEO) {
+ av_assert0( inlink-> in_color_ranges->refcount > 0);
+ av_assert0( inlink->out_color_ranges->refcount > 0);
+ av_assert0(outlink-> in_color_ranges->refcount > 0);
+ av_assert0(outlink->out_color_ranges->refcount > 0);
+ }
if (outlink->type == AVMEDIA_TYPE_AUDIO) {
av_assert0( inlink-> in_samplerates->refcount > 0);
av_assert0( inlink->out_samplerates->refcount > 0);
@@ -588,6 +622,12 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx)
if (!ff_merge_formats( inlink->in_formats, inlink->out_formats, inlink->type) ||
!ff_merge_formats(outlink->in_formats, outlink->out_formats, outlink->type))
ret = AVERROR(ENOSYS);
+ if (inlink->type == AVMEDIA_TYPE_VIDEO &&
+ (!ff_merge_samplerates(inlink->in_color_ranges, inlink->out_color_ranges)))
+ ret = AVERROR(ENOSYS);
+ if (outlink->type == AVMEDIA_TYPE_VIDEO &&
+ (!ff_merge_samplerates(outlink->in_color_ranges, outlink->out_color_ranges)))
+ ret = AVERROR(ENOSYS);
if (inlink->type == AVMEDIA_TYPE_AUDIO &&
(!ff_merge_samplerates(inlink->in_samplerates,
inlink->out_samplerates) ||
@@ -709,6 +749,17 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref)
link->in_formats->nb_formats = 1;
link->format = link->in_formats->formats[0];
+ if (link->type == AVMEDIA_TYPE_VIDEO) {
+ if (!link->in_color_ranges->nb_formats) {
+ av_log(link->src, AV_LOG_ERROR, "Cannot select color range for"
+ " the link between filters %s and %s.\n", link->src->name,
+ link->dst->name);
+ return AVERROR(EINVAL);
+ }
+ link->in_color_ranges->nb_formats = 1;
+ link->color_range = link->in_color_ranges->formats[0];
+ }
+
if (link->type == AVMEDIA_TYPE_AUDIO) {
if (!link->in_samplerates->nb_formats) {
av_log(link->src, AV_LOG_ERROR, "Cannot select sample rate for"
@@ -739,6 +790,8 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref)
ff_formats_unref(&link->in_formats);
ff_formats_unref(&link->out_formats);
+ ff_formats_unref(&link->in_color_ranges);
+ ff_formats_unref(&link->out_color_ranges);
ff_formats_unref(&link->in_samplerates);
ff_formats_unref(&link->out_samplerates);
ff_channel_layouts_unref(&link->in_channel_layouts);
diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c
index 897396cac4..f3abb7de6e 100644
--- a/libavfilter/buffersink.c
+++ b/libavfilter/buffersink.c
@@ -45,6 +45,8 @@ typedef struct BufferSinkContext {
/* only used for video */
enum AVPixelFormat *pixel_fmts; ///< list of accepted pixel formats, must be terminated with -1
int pixel_fmts_size;
+ enum AVColorRange *color_ranges; ///< list of accepted color ranges, must be terminated with 0
+ int color_ranges_size;
/* only used for audio */
enum AVSampleFormat *sample_fmts; ///< list of accepted sample formats, terminated by AV_SAMPLE_FMT_NONE
@@ -130,11 +132,13 @@ int attribute_align_arg av_buffersink_get_samples(AVFilterContext *ctx,
AVBufferSinkParams *av_buffersink_params_alloc(void)
{
static const int pixel_fmts[] = { AV_PIX_FMT_NONE };
+ static const enum AVColorRange color_ranges[] = { AVCOL_RANGE_UNSPECIFIED };
AVBufferSinkParams *params = av_malloc(sizeof(AVBufferSinkParams));
if (!params)
return NULL;
params->pixel_fmts = pixel_fmts;
+ params->color_ranges = color_ranges;
return params;
}
@@ -211,6 +215,8 @@ static av_cold int vsink_init(AVFilterContext *ctx, void *opaque)
if (params) {
if ((ret = av_opt_set_int_list(buf, "pix_fmts", params->pixel_fmts, AV_PIX_FMT_NONE, 0)) < 0)
return ret;
+ if ((ret = av_opt_set_int_list(buf, "color_ranges", params->color_ranges, AVCOL_RANGE_UNSPECIFIED, 0)) < 0)
+ return ret;
}
return common_init(ctx);
@@ -227,16 +233,25 @@ static int vsink_query_formats(AVFilterContext *ctx)
{
BufferSinkContext *buf = ctx->priv;
AVFilterFormats *formats = NULL;
+ AVFilterFormats *color_ranges = NULL;
unsigned i;
int ret;
CHECK_LIST_SIZE(pixel_fmts)
+ CHECK_LIST_SIZE(color_ranges)
if (buf->pixel_fmts_size) {
for (i = 0; i < NB_ITEMS(buf->pixel_fmts); i++)
if ((ret = ff_add_format(&formats, buf->pixel_fmts[i])) < 0)
return ret;
if ((ret = ff_set_common_formats(ctx, formats)) < 0)
return ret;
+ }
+ if (buf->color_ranges_size) {
+ for (i = 0; i < NB_ITEMS(buf->color_ranges); i++)
+ if ((ret = ff_add_format(&color_ranges, buf->color_ranges[i])) < 0)
+ return ret;
+ if ((ret = ff_set_common_color_ranges(ctx, color_ranges)) < 0)
+ return ret;
} else {
if ((ret = ff_default_query_formats(ctx)) < 0)
return ret;
@@ -318,6 +333,7 @@ static int asink_query_formats(AVFilterContext *ctx)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
static const AVOption buffersink_options[] = {
{ "pix_fmts", "set the supported pixel formats", OFFSET(pixel_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS },
+ { "color_ranges", "set the supported color ranges", OFFSET(color_ranges), AV_OPT_TYPE_BINARY, .flags = FLAGS },
{ NULL },
};
#undef FLAGS
diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h
index e6d6504832..300a7bfb3a 100644
--- a/libavfilter/buffersink.h
+++ b/libavfilter/buffersink.h
@@ -64,6 +64,7 @@ int av_buffersink_get_frame_flags(AVFilterContext *ctx, AVFrame *frame, int flag
*/
typedef struct AVBufferSinkParams {
const enum AVPixelFormat *pixel_fmts; ///< list of allowed pixel formats, terminated by AV_PIX_FMT_NONE
+ const enum AVColorRange *color_ranges; ///< list of allowed color ranges, terminated by AVCOL_RANGE_UNSPECIFIED
} AVBufferSinkParams;
/**
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c
index 51a1a9fb49..e450a2bca7 100644
--- a/libavfilter/buffersrc.c
+++ b/libavfilter/buffersrc.c
@@ -412,6 +412,7 @@ static int query_formats(AVFilterContext *ctx)
BufferSourceContext *c = ctx->priv;
AVFilterChannelLayouts *channel_layouts = NULL;
AVFilterFormats *formats = NULL;
+ AVFilterFormats *color_ranges = NULL;
AVFilterFormats *samplerates = NULL;
int ret;
@@ -420,6 +421,9 @@ 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;
+ 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/formats.c b/libavfilter/formats.c
index 20a2c89719..4e20f9c771 100644
--- a/libavfilter/formats.c
+++ b/libavfilter/formats.c
@@ -262,11 +262,11 @@ int ff_fmt_is_in(int fmt, const int *fmts)
return 0;
}
-#define MAKE_FORMAT_LIST(type, field, count_field) \
+#define MAKE_FORMAT_LIST(type, field, count_field, end) \
type *formats; \
int count = 0; \
if (fmts) \
- for (count = 0; fmts[count] != -1; count++) \
+ for (count = 0; fmts[count] != end; count++) \
; \
formats = av_mallocz(sizeof(*formats)); \
if (!formats) \
@@ -282,7 +282,16 @@ int ff_fmt_is_in(int fmt, const int *fmts)
AVFilterFormats *ff_make_format_list(const int *fmts)
{
- MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats);
+ MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats, -1);
+ while (count--)
+ formats->formats[count] = fmts[count];
+
+ return formats;
+}
+
+AVFilterFormats *ff_make_color_range_list(const int *fmts)
+{
+ MAKE_FORMAT_LIST(AVFilterFormats, formats, nb_formats, AVCOL_RANGE_UNSPECIFIED);
while (count--)
formats->formats[count] = fmts[count];
@@ -292,7 +301,7 @@ AVFilterFormats *ff_make_format_list(const int *fmts)
AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
{
MAKE_FORMAT_LIST(AVFilterChannelLayouts,
- channel_layouts, nb_channel_layouts);
+ channel_layouts, nb_channel_layouts, -1);
if (count)
memcpy(formats->channel_layouts, fmts,
sizeof(*formats->channel_layouts) * count);
@@ -303,7 +312,7 @@ AVFilterChannelLayouts *ff_make_formatu64_list(const uint64_t *fmts)
AVFilterChannelLayouts *avfilter_make_format64_list(const int64_t *fmts)
{
MAKE_FORMAT_LIST(AVFilterChannelLayouts,
- channel_layouts, nb_channel_layouts);
+ channel_layouts, nb_channel_layouts, -1);
if (count)
memcpy(formats->channel_layouts, fmts,
sizeof(*formats->channel_layouts) * count);
@@ -398,6 +407,39 @@ AVFilterFormats *ff_all_samplerates(void)
return ret;
}
+AVFilterFormats *ff_jpeg_color_ranges(void)
+{
+ AVFilterFormats *ret = NULL;
+
+ if (ff_add_format(&ret, AVCOL_RANGE_JPEG) < 0)
+ return NULL;
+
+ return ret;
+}
+
+AVFilterFormats *ff_mpeg_color_ranges(void)
+{
+ AVFilterFormats *ret = NULL;
+
+ if (ff_add_format(&ret, AVCOL_RANGE_MPEG) < 0)
+ return NULL;
+
+ return ret;
+}
+
+AVFilterFormats *ff_all_color_ranges(void)
+{
+ AVFilterFormats *fmts = NULL;
+
+ if (ff_add_format(&fmts, AVCOL_RANGE_MPEG) < 0)
+ return NULL;
+ if (ff_add_format(&fmts, AVCOL_RANGE_JPEG) < 0)
+ return NULL;
+ if (ff_add_format(&fmts, AVCOL_RANGE_UNSPECIFIED) < 0)
+ return NULL;
+ return fmts;
+}
+
AVFilterChannelLayouts *ff_all_channel_layouts(void)
{
AVFilterChannelLayouts *ret = av_mallocz(sizeof(*ret));
@@ -560,6 +602,13 @@ int ff_set_common_samplerates(AVFilterContext *ctx,
ff_formats_ref, ff_formats_unref, formats);
}
+int ff_set_common_color_ranges(AVFilterContext *ctx,
+ AVFilterFormats *color_ranges)
+{
+ SET_COMMON_FORMATS(ctx, color_ranges, in_color_ranges, out_color_ranges,
+ ff_formats_ref, ff_formats_unref, formats);
+}
+
/**
* A helper for query_formats() which sets all links to the same list of
* formats. If there are no links hooked to this filter, the list of formats is
@@ -590,6 +639,11 @@ static int default_query_formats_common(AVFilterContext *ctx,
if (ret < 0)
return ret;
}
+ if (type == AVMEDIA_TYPE_VIDEO) {
+ ret = ff_set_common_color_ranges(ctx, ff_all_color_ranges());
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
@@ -659,6 +713,17 @@ int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx)
return 0;
}
+int ff_parse_color_range(enum AVColorRange *ret, const char *arg, void *log_ctx)
+{
+ int color_range = av_color_range_from_name(arg);
+ if (color_range < 0) {
+ av_log(log_ctx, AV_LOG_ERROR, "Invalid color range '%s'\n", arg);
+ return AVERROR(EINVAL);
+ }
+ *ret = color_range;
+ return 0;
+}
+
int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg,
void *log_ctx)
{
diff --git a/libavfilter/formats.h b/libavfilter/formats.h
index 870809b5a0..6706f76dce 100644
--- a/libavfilter/formats.h
+++ b/libavfilter/formats.h
@@ -166,6 +166,9 @@ av_warn_unused_result
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats);
av_warn_unused_result
+int ff_set_common_color_ranges(AVFilterContext *ctx, AVFilterFormats *color_ranges);
+
+av_warn_unused_result
int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout);
/**
@@ -205,6 +208,16 @@ av_warn_unused_result
AVFilterFormats *ff_make_format_list(const int *fmts);
/**
+ * Create a list of supported color ranges. This is intended for use in
+ * AVFilter->query_formats().
+ *
+ * @param fmts list of color ranges, terminated by -1
+ * @return the format list, with no existing references
+ */
+av_warn_unused_result
+AVFilterFormats *ff_make_color_range_list(const int *color_ranges);
+
+/**
* Add fmt to the list of media formats contained in *avff.
* If *avff is NULL the function allocates the filter formats struct
* and puts its pointer in *avff.
@@ -222,6 +235,24 @@ av_warn_unused_result
AVFilterFormats *ff_all_formats(enum AVMediaType type);
/**
+ * Return a list of all color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_all_color_ranges(void);
+
+/**
+ * Return a list of all mpeg color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_mpeg_color_ranges(void);
+
+/**
+ * Return a list of all jpeg color ranges supported by FFmpeg.
+ */
+av_warn_unused_result
+AVFilterFormats *ff_jpeg_color_ranges(void);
+
+/**
* Construct a formats list containing all planar sample formats.
*/
av_warn_unused_result
diff --git a/libavfilter/internal.h b/libavfilter/internal.h
index f9679ed1d7..15fd3ff99b 100644
--- a/libavfilter/internal.h
+++ b/libavfilter/internal.h
@@ -191,6 +191,17 @@ av_warn_unused_result
int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx);
/**
+ * Parse a color range.
+ *
+ * @param ret unsigned enum pointer to where the value should be written
+ * @param arg string to parse
+ * @param log_ctx log context
+ * @return >= 0 in case of success, a negative AVERROR code on error
+ */
+av_warn_unused_result
+int ff_parse_color_range(enum AVColorRange *ret, const char *arg, void *log_ctx);
+
+/**
* Parse a time base.
*
* @param ret unsigned AVRational pointer to where the value should be written
diff --git a/libavfilter/vf_format.c b/libavfilter/vf_format.c
index a57c99d797..420a01ec8a 100644
--- a/libavfilter/vf_format.c
+++ b/libavfilter/vf_format.c
@@ -38,18 +38,21 @@
typedef struct FormatContext {
const AVClass *class;
char *pix_fmts;
+ char *color_ranges_str;
/**
* pix_fmts parsed into AVPixelFormats and terminated with
* AV_PIX_FMT_NONE
*/
enum AVPixelFormat *formats;
+ enum AVColorRange *color_ranges;
} FormatContext;
static av_cold void uninit(AVFilterContext *ctx)
{
FormatContext *s = ctx->priv;
av_freep(&s->formats);
+ av_freep(&s->color_ranges);
}
static av_cold int init(AVFilterContext *ctx)
@@ -57,6 +60,7 @@ static av_cold int init(AVFilterContext *ctx)
FormatContext *s = ctx->priv;
char *cur, *sep;
int nb_formats = 1;
+ int nb_color_ranges = 1;
int i;
int ret;
@@ -91,6 +95,37 @@ static av_cold int init(AVFilterContext *ctx)
}
s->formats[nb_formats] = AV_PIX_FMT_NONE;
+ if (!s->color_ranges_str) {
+ av_log(ctx, AV_LOG_ERROR, "Empty output color range string.\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* count the color ranges */
+ cur = s->color_ranges_str;
+ while ((cur = strchr(cur, '|'))) {
+ nb_color_ranges++;
+ if (*cur)
+ cur++;
+ }
+
+ s->color_ranges = av_malloc_array(nb_color_ranges + 1, sizeof(*s->color_ranges));
+ if (!s->color_ranges)
+ return AVERROR(ENOMEM);
+
+ /* parse the list of formats */
+ cur = s->color_ranges_str;
+ for (i = 0; i < nb_color_ranges; i++) {
+ sep = strchr(cur, '|');
+ if (sep)
+ *sep++ = 0;
+
+ if ((ret = ff_parse_color_range(&s->color_ranges[i], cur, ctx)) < 0)
+ return ret;
+
+ cur = sep;
+ }
+ s->color_ranges[nb_color_ranges] = -1;
+
if (!strcmp(ctx->filter->name, "noformat")) {
const AVPixFmtDescriptor *desc = NULL;
enum AVPixelFormat *formats_allowed;
@@ -130,17 +165,26 @@ static int query_formats(AVFilterContext *ctx)
{
FormatContext *s = ctx->priv;
AVFilterFormats *formats = ff_make_format_list(s->formats);
+ AVFilterFormats *color_ranges = ff_make_color_range_list(s->color_ranges);
+ int ret;
if (!formats)
return AVERROR(ENOMEM);
- return ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ if (!color_ranges)
+ return AVERROR(ENOMEM);
+ return ff_set_common_color_ranges(ctx, color_ranges);
}
#define OFFSET(x) offsetof(FormatContext, x)
static const AVOption options[] = {
{ "pix_fmts", "A '|'-separated list of pixel formats", OFFSET(pix_fmts), AV_OPT_TYPE_STRING, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
+ { "color_ranges", "A '|'-separated list of color ranges", OFFSET(color_ranges_str), AV_OPT_TYPE_STRING, {.str = "unknown"}, .flags = AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM },
{ NULL }
};
diff --git a/libavfilter/vf_noise.c b/libavfilter/vf_noise.c
index abdf04708b..c7af77b669 100644
--- a/libavfilter/vf_noise.c
+++ b/libavfilter/vf_noise.c
@@ -142,7 +142,11 @@ static int query_formats(AVFilterContext *ctx)
return ret;
}
- return ff_set_common_formats(ctx, formats);
+ ret = ff_set_common_formats(ctx, formats);
+ if (ret < 0)
+ return ret;
+
+ return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
}
static int config_input(AVFilterLink *inlink)
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 802f841cc3..af5edd5146 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -157,7 +157,9 @@ static av_cold void uninit(AVFilterContext *ctx)
static int query_formats(AVFilterContext *ctx)
{
+ ScaleContext *scale = ctx->priv;
AVFilterFormats *formats;
+ AVFilterFormats *color_ranges;
enum AVPixelFormat pix_fmt;
int ret;
@@ -174,10 +176,14 @@ static int query_formats(AVFilterContext *ctx)
}
if ((ret = ff_formats_ref(formats, &ctx->inputs[0]->out_formats)) < 0)
return ret;
+ color_ranges = ff_all_color_ranges();
+ if ((ret = ff_formats_ref(color_ranges, &ctx->inputs[0]->out_color_ranges)) < 0)
+ return ret;
}
if (ctx->outputs[0]) {
const AVPixFmtDescriptor *desc = NULL;
formats = NULL;
+ color_ranges = NULL;
while ((desc = av_pix_fmt_desc_next(desc))) {
pix_fmt = av_pix_fmt_desc_get_id(desc);
if ((sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8 ||
@@ -188,6 +194,10 @@ static int query_formats(AVFilterContext *ctx)
}
if ((ret = ff_formats_ref(formats, &ctx->outputs[0]->in_formats)) < 0)
return ret;
+
+ color_ranges = ff_all_color_ranges();
+ if ((ret = ff_formats_ref(color_ranges, &ctx->outputs[0]->in_color_ranges)) < 0)
+ return ret;
}
return 0;
@@ -276,6 +286,7 @@ static int config_props(AVFilterLink *outlink)
scale->isws[0] = scale->isws[1] = scale->sws = NULL;
if (inlink0->w == outlink->w &&
inlink0->h == outlink->h &&
+ inlink0->color_range == outlink->color_range &&
!scale->out_color_matrix &&
scale->in_range == scale->out_range &&
inlink0->format == outlink->format)
@@ -348,11 +359,11 @@ static int config_props(AVFilterLink *outlink)
} else
outlink->sample_aspect_ratio = inlink0->sample_aspect_ratio;
- av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
+ av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d cr:%d -> w:%d h:%d fmt:%s sar:%d/%d cr:%d flags:0x%0x\n",
inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
- inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
+ inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, inlink->color_range,
outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
- outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
+ outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, outlink->color_range,
scale->flags);
return 0;
diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c
index a790974d14..fddd7f55ee 100644
--- a/libavfilter/vsrc_testsrc.c
+++ b/libavfilter/vsrc_testsrc.c
@@ -207,7 +207,13 @@ static av_cold int color_init(AVFilterContext *ctx)
static int color_query_formats(AVFilterContext *ctx)
{
- return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ int ret;
+
+ ret = ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
+ if (ret < 0)
+ return ret;
+
+ return ff_set_common_color_ranges(ctx, ff_mpeg_color_ranges());
}
static int color_config_props(AVFilterLink *inlink)
@@ -653,11 +659,16 @@ static int test_query_formats(AVFilterContext *ctx)
static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_RGB24, 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);
+ ret = ff_set_common_formats(ctx, fmts_list);
+ if (ret < 0)
+ return ret;
+
+ return ff_set_common_color_ranges(ctx, ff_all_color_ranges());
}
static const AVFilterPad avfilter_vsrc_testsrc_outputs[] = {
diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak
index c19f301ff8..24c96ffced 100644
--- a/tests/fate/filter-video.mak
+++ b/tests/fate/filter-video.mak
@@ -1,5 +1,5 @@
FATE_FILTER_SAMPLES-$(call ALLYES, SMJPEG_DEMUXER MJPEG_DECODER PERMS_FILTER OWDENOISE_FILTER) += fate-filter-owdenoise-sample
-fate-filter-owdenoise-sample: CMD = ffmpeg -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -vf "trim=duration=0.5,perms=random,owdenoise=10:20:20:enable=not(between(t\,0.2\,1.2))" -an -f rawvideo -
+fate-filter-owdenoise-sample: CMD = ffmpeg -idct simple -i $(TARGET_SAMPLES)/smjpeg/scenwin.mjpg -vf "trim=duration=0.5,perms=random,owdenoise=10:20:20:enable=not(between(t\,0.2\,1.2)),format=yuv420p:tv" -an -f rawvideo -
fate-filter-owdenoise-sample: REF = $(TARGET_SAMPLES)/filter-reference/owdenoise-scenwin.raw
fate-filter-owdenoise-sample: CMP_TARGET = 1
fate-filter-owdenoise-sample: FUZZ = 3539
diff --git a/tests/fate/pixlet.mak b/tests/fate/pixlet.mak
index c720f32616..e42c06d194 100644
--- a/tests/fate/pixlet.mak
+++ b/tests/fate/pixlet.mak
@@ -1,5 +1,5 @@
FATE_PIXLET += fate-pixlet-rgb
-fate-pixlet-rgb: CMD = framecrc -i $(TARGET_SAMPLES)/pixlet/pixlet_rgb.mov -an -pix_fmt yuv420p16le
+fate-pixlet-rgb: CMD = framecrc -i $(TARGET_SAMPLES)/pixlet/pixlet_rgb.mov -an -vf format=yuv420p16le:pc
FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, PIXLET) += $(FATE_PIXLET)
fate-pixlet: $(FATE_PIXLET)
--
2.11.0
More information about the ffmpeg-devel
mailing list