颜色空间转换有很多相关标准:
https://docs.opencv.org/3.4.0/de/d25/imgproc_color_conversions.html
https://www.itu.int/rec/R-REC-BT.601-4-199407-S/en
ffmpeg命令行颜色空间转换是通过调用vf_scale中的swscale来进行转码。
我们通过gdb来调试ffmpeg.
首先编译ffmpeg n4.5.编译脚本如下:
./configure \
--prefix=/workspace/FFmpeg-n4.5-dev/libffmpeg \
--enable-shared \
--disable-static \
--extra-cflags=-g \
--enable-debug \
--disable-optimizations \
--disable-stripping
make -j8
make install
编译后我们找到ffmpeg_g来进行追踪。
gdb ./ffmpeg_g
set args -y -i /workspace/libx264_640x360_baseline_5_frames.h264 "scale=in_color_matrix=bt601:in_range=2" -pix_fmt bgr24 ffmpeg-bgr24.rgb
b yuv2rgb.c:ff_yuv2rgb_get_func_ptr
ffmpeg调用栈如下:
下面这个是初始化调用,最后调用到ff_yuv2rgb_get_func_ptr

下面是正常csc中调用流程:

ifilter_send_frame()
configure_filtergraph(fg)
avfilter_graph_config(fg->graph, NULL))
graph_config_links(graphctx, log_ctx))
avfilter_config_links(filt))
config_link(link)->config_props(AVFilterLink *outlink)
sws_init_context(*s, NULL, NULL))
上面調用了:
static const AVClass scale_class = {
.class_name = "scale",
.item_name = av_default_item_name,
.option = scale_options,
.version = LIBAVUTIL_VERSION_INT,
.category = AV_CLASS_CATEGORY_FILTER,
#if FF_API_CHILD_CLASS_NEXT
.child_class_next = child_class_next,
#endif
.child_class_iterate = child_class_iterate,
};
static const AVFilterPad avfilter_vf_scale_inputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.filter_frame = filter_frame,
},
{
NULL }
};
static const AVFilterPad avfilter_vf_scale_outputs[] = {
{
.name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.config_props = config_props,
},
{
NULL }
};
AVFilter ff_vf_scale = {
.name = "scale",
.description = NULL_IF_CONFIG_SMALL("Scale the input video size and/or convert the image format."),
.init_dict = init_dict,
.uninit = uninit,
.query_formats = query_formats,
.priv_size = sizeof(ScaleContext),
.priv_class = &scale_class,
.inputs = avfilter_vf_scale_inputs,
.outputs = avfilter_vf_scale_outputs,
.process_command = process_command,
};
下面是调用inid_dict的调用栈:

下面是调用:parse_yuv_type()

static const int *parse_yuv_type(const char *s, enum AVColorSpace colorspace)
{
printf("parse_yuv_type=%s>>>>>>>>\n",s);
if (!s)
s = "bt601";
if (s && strstr(s, "bt709")) {
colorspace = AVCOL_SPC_BT709;
} else if (s && strstr(s, "fcc")) {
colorspace = AVCOL_SPC_FCC;
} else if (s && strstr(s, "smpte240m")) {
colorspace = AVCOL_SPC_SMPTE240M;
} else if (s && (strstr(s, "bt601") || strstr(s, "bt470") || strstr(s, "smpte170m"))) {
colorspace = AVCOL_SPC_BT470BG;
} else if (s && strstr(s, "bt2020")) {
colorspace = AVCOL_SPC_BT2020_NCL;
}
if (colorspace < 1 || colorspace > 10 || colorspace == 8) {
colorspace = AVCOL_SPC_BT470BG;
}
printf("colorspace=%d>>>>>>>>\n",colorspace);
return sws_getCoefficients(colorspace);
}
static int scale_frame(AVFilterLink *link, AVFrame *in, AVFrame **frame_out)
{
AVFilterContext *ctx = link->dst;
ScaleContext *scale = ctx->priv;
AVFilterLink *outlink = ctx->outputs[0];
AVFrame *out;
...
scale:
if (!scale->sws) {
*frame_out = in;
return 0;
}
...
in_range = in->color_range;
if ( scale->in_color_matrix
|| scale->out_color_matrix
|| scale-> in_range != AVCOL_RANGE_UNSPECIFIED
|| in_range != AVCOL_RANGE_UNSPECIFIED
|| scale->out_range != AVCOL_RANGE_UNSPECIFIED) {
int in_full, out_full, brightness, contrast, saturation;
const int *inv_table, *table;
sws_getColorspaceDetails(scale->sws, (int **)&inv_table, &in_full,
(int **)&table, &out_full,
&brightness, &contrast, &saturation);
//这里使用了两个输入矩阵设置,因为in_color_matrix和out_color_matrix默认是auto,所以外边设置了out_color_matrix
//之后是没有用的,好奇怪
if (scale->in_color_matrix)
inv_table = parse_yuv_type(scale->in_color_matrix, in->colorspace);
if

文章详细介绍了ffmpeg如何通过swscale库进行颜色空间转换,包括配置滤镜、调用栈、颜色矩阵解析以及使用查表法进行YUV到RGB的转换过程。主要关注的是ffmpeg命令行工具在处理视频帧时内部的色彩空间配置和转换算法。
最低0.47元/天 解锁文章
3580

被折叠的 条评论
为什么被折叠?



