ffmpeg 颜色空间转换分析

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

颜色空间转换有很多相关标准:
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
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值