ffmpeg 颜色空间转换分析

news2025/2/28 6:35:40

颜色空间转换有很多相关标准:
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 (scale->out_color_matrix)
            table     = parse_yuv_type(scale->out_color_matrix, AVCOL_SPC_UNSPECIFIED);
        else if (scale->in_color_matrix)
            table = inv_table;

        if (scale-> in_range != AVCOL_RANGE_UNSPECIFIED)
            in_full  = (scale-> in_range == AVCOL_RANGE_JPEG);
        else if (in_range != AVCOL_RANGE_UNSPECIFIED)
            in_full  = (in_range == AVCOL_RANGE_JPEG);
        if (scale->out_range != AVCOL_RANGE_UNSPECIFIED)
            out_full = (scale->out_range == AVCOL_RANGE_JPEG);

        sws_setColorspaceDetails(scale->sws, inv_table, in_full,
                                 table, out_full,
                                 brightness, contrast, saturation);
        if (scale->isws[0])
            sws_setColorspaceDetails(scale->isws[0], inv_table, in_full,
                                     table, out_full,
                                     brightness, contrast, saturation);
        if (scale->isws[1])
            sws_setColorspaceDetails(scale->isws[1], inv_table, in_full,
                                     table, out_full,
                                     brightness, contrast, saturation);

        out->color_range = out_full ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
    }

    av_reduce(&out->sample_aspect_ratio.num, &out->sample_aspect_ratio.den,
              (int64_t)in->sample_aspect_ratio.num * outlink->h * link->w,
              (int64_t)in->sample_aspect_ratio.den * outlink->w * link->h,
              INT_MAX);

    if (scale->interlaced>0 || (scale->interlaced<0 && in->interlaced_frame)) {
        scale_slice(link, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
        scale_slice(link, out, in, scale->isws[1], 0,  link->h   /2, 2, 1);
    } else if (scale->nb_slices) {
        int i, slice_h, slice_start, slice_end = 0;
        const int nb_slices = FFMIN(scale->nb_slices, link->h);
        for (i = 0; i < nb_slices; i++) {
            slice_start = slice_end;
            slice_end   = (link->h * (i+1)) / nb_slices;
            slice_h     = slice_end - slice_start;
            scale_slice(link, out, in, scale->sws, slice_start, slice_h, 1, 0);
        }
    } else {
        scale_slice(link, out, in, scale->sws, 0, link->h, 1, 0);
    }

    av_frame_free(&in);
    return 0;
}

最终是调用yuv2rgb_c_24_bgr():

这个命令可以简单的将宏展开
gcc -E -P file.c >> out.c

ffmpeg swscale颜色空间转换是采用查表法,用了4个表,具体可以看代码查看具体算法


#define YUVRGB_TABLE_HEADROOM 512
#define YUVRGB_TABLE_LUMA_HEADROOM 512

static int yuv2rgb_c_24_bgr(SwsContext *c, const uint8_t *src[], int srcStride[],
    int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) {
    int y;
    if (!0 && c->srcFormat == AV_PIX_FMT_YUV422P) {
        srcStride[1] *= 2;
        srcStride[2] *= 2;
    }
    for (y = 0; y < srcSliceH; y += 2) {
        int            yd    = y + srcSliceY;
        uint8_t *      dst_1 = (uint8_t *)(dst[0] + (yd)*dstStride[0]);
        uint8_t *      dst_2 = (uint8_t *)(dst[0] + (yd + 1) * dstStride[0]);
        uint8_t *      r, *g, *b;
        const uint8_t *py_1 = src[0] + y * srcStride[0];
        const uint8_t *py_2 = py_1 + srcStride[0];
        const uint8_t *pu   = src[1] + (y >> 1) * srcStride[1];
        const uint8_t *pv   = src[2] + (y >> 1) * srcStride[2];
        const uint8_t *pa_1, *pa_2;
        unsigned int   h_size = c->dstW >> 3;
        if (0) {
            pa_1 = src[3] + y * srcStride[3];
            pa_2 = pa_1 + srcStride[3];
        }

        while (h_size--) {
            int U, V, Y;
            U = pu[0];
            V = pv[0];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_1[2 * 0];
            dst_1[6 * 0 + 0] = b[Y];
            dst_1[6 * 0 + 1] = g[Y];
            dst_1[6 * 0 + 2] = r[Y];
            Y                = py_1[2 * 0 + 1];
            dst_1[6 * 0 + 3] = b[Y];
            dst_1[6 * 0 + 4] = g[Y];
            dst_1[6 * 0 + 5] = r[Y];
            ;
            Y                = py_2[2 * 0];
            dst_2[6 * 0 + 0] = b[Y];
            dst_2[6 * 0 + 1] = g[Y];
            dst_2[6 * 0 + 2] = r[Y];
            Y                = py_2[2 * 0 + 1];
            dst_2[6 * 0 + 3] = b[Y];
            dst_2[6 * 0 + 4] = g[Y];
            dst_2[6 * 0 + 5] = r[Y];
            ;
            U = pu[1];
            V = pv[1];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_2[2 * 1];
            dst_2[6 * 1 + 0] = b[Y];
            dst_2[6 * 1 + 1] = g[Y];
            dst_2[6 * 1 + 2] = r[Y];
            Y                = py_2[2 * 1 + 1];
            dst_2[6 * 1 + 3] = b[Y];
            dst_2[6 * 1 + 4] = g[Y];
            dst_2[6 * 1 + 5] = r[Y];
            ;
            Y                = py_1[2 * 1];
            dst_1[6 * 1 + 0] = b[Y];
            dst_1[6 * 1 + 1] = g[Y];
            dst_1[6 * 1 + 2] = r[Y];
            Y                = py_1[2 * 1 + 1];
            dst_1[6 * 1 + 3] = b[Y];
            dst_1[6 * 1 + 4] = g[Y];
            dst_1[6 * 1 + 5] = r[Y];
            ;
            U = pu[2];
            V = pv[2];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_1[2 * 2];
            dst_1[6 * 2 + 0] = b[Y];
            dst_1[6 * 2 + 1] = g[Y];
            dst_1[6 * 2 + 2] = r[Y];
            Y                = py_1[2 * 2 + 1];
            dst_1[6 * 2 + 3] = b[Y];
            dst_1[6 * 2 + 4] = g[Y];
            dst_1[6 * 2 + 5] = r[Y];
            ;
            Y                = py_2[2 * 2];
            dst_2[6 * 2 + 0] = b[Y];
            dst_2[6 * 2 + 1] = g[Y];
            dst_2[6 * 2 + 2] = r[Y];
            Y                = py_2[2 * 2 + 1];
            dst_2[6 * 2 + 3] = b[Y];
            dst_2[6 * 2 + 4] = g[Y];
            dst_2[6 * 2 + 5] = r[Y];
            ;
            U = pu[3];
            V = pv[3];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_2[2 * 3];
            dst_2[6 * 3 + 0] = b[Y];
            dst_2[6 * 3 + 1] = g[Y];
            dst_2[6 * 3 + 2] = r[Y];
            Y                = py_2[2 * 3 + 1];
            dst_2[6 * 3 + 3] = b[Y];
            dst_2[6 * 3 + 4] = g[Y];
            dst_2[6 * 3 + 5] = r[Y];
            ;
            Y                = py_1[2 * 3];
            dst_1[6 * 3 + 0] = b[Y];
            dst_1[6 * 3 + 1] = g[Y];
            dst_1[6 * 3 + 2] = r[Y];
            Y                = py_1[2 * 3 + 1];
            dst_1[6 * 3 + 3] = b[Y];
            dst_1[6 * 3 + 4] = g[Y];
            dst_1[6 * 3 + 5] = r[Y];
            ;
            pu += 4 >> 0;
            pv += 4 >> 0;
            py_1 += 8 >> 0;
            py_2 += 8 >> 0;
            dst_1 += 24 >> 0;
            dst_2 += 24 >> 0;
        }

        if (c->dstW & (4 >> 0)) {
            int av_unused Y, U, V;
            U = pu[0];
            V = pv[0];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_1[2 * 0];
            dst_1[6 * 0 + 0] = b[Y];
            dst_1[6 * 0 + 1] = g[Y];
            dst_1[6 * 0 + 2] = r[Y];
            Y                = py_1[2 * 0 + 1];
            dst_1[6 * 0 + 3] = b[Y];
            dst_1[6 * 0 + 4] = g[Y];
            dst_1[6 * 0 + 5] = r[Y];
            ;
            Y                = py_2[2 * 0];
            dst_2[6 * 0 + 0] = b[Y];
            dst_2[6 * 0 + 1] = g[Y];
            dst_2[6 * 0 + 2] = r[Y];
            Y                = py_2[2 * 0 + 1];
            dst_2[6 * 0 + 3] = b[Y];
            dst_2[6 * 0 + 4] = g[Y];
            dst_2[6 * 0 + 5] = r[Y];
            ;
            U = pu[1];
            V = pv[1];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_2[2 * 1];
            dst_2[6 * 1 + 0] = b[Y];
            dst_2[6 * 1 + 1] = g[Y];
            dst_2[6 * 1 + 2] = r[Y];
            Y                = py_2[2 * 1 + 1];
            dst_2[6 * 1 + 3] = b[Y];
            dst_2[6 * 1 + 4] = g[Y];
            dst_2[6 * 1 + 5] = r[Y];
            ;
            Y                = py_1[2 * 1];
            dst_1[6 * 1 + 0] = b[Y];
            dst_1[6 * 1 + 1] = g[Y];
            dst_1[6 * 1 + 2] = r[Y];
            Y                = py_1[2 * 1 + 1];
            dst_1[6 * 1 + 3] = b[Y];
            dst_1[6 * 1 + 4] = g[Y];
            dst_1[6 * 1 + 5] = r[Y];
            ;
            pu += 4 >> 1;
            pv += 4 >> 1;
            py_1 += 8 >> 1;
            py_2 += 8 >> 1;
            dst_1 += 24 >> 1;
            dst_2 += 24 >> 1;
        }

        if (c->dstW & (4 >> 1)) {
            int av_unused Y, U, V;
            U = pu[0];
            V = pv[0];
            r = (void *)c->table_rV[V + YUVRGB_TABLE_HEADROOM];
            g = (void *)(c->table_gU[U + YUVRGB_TABLE_HEADROOM] +
                         c->table_gV[V + YUVRGB_TABLE_HEADROOM]);
            b = (void *)c->table_bU[U + YUVRGB_TABLE_HEADROOM];
            ;
            Y                = py_1[2 * 0];
            dst_1[6 * 0 + 0] = b[Y];
            dst_1[6 * 0 + 1] = g[Y];
            dst_1[6 * 0 + 2] = r[Y];
            Y                = py_1[2 * 0 + 1];
            dst_1[6 * 0 + 3] = b[Y];
            dst_1[6 * 0 + 4] = g[Y];
            dst_1[6 * 0 + 5] = r[Y];
            ;
            Y                = py_2[2 * 0];
            dst_2[6 * 0 + 0] = b[Y];
            dst_2[6 * 0 + 1] = g[Y];
            dst_2[6 * 0 + 2] = r[Y];
            Y                = py_2[2 * 0 + 1];
            dst_2[6 * 0 + 3] = b[Y];
            dst_2[6 * 0 + 4] = g[Y];
            dst_2[6 * 0 + 5] = r[Y];
            ;
        }
    }
    return srcSliceH;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/155555.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Getting Started with NLP》chap11:Named-entity recognition

《Getting Started with NLP》chap11&#xff1a;Named-entity recognition 最近需要做一些NER相关的任务&#xff0c;来学习一下这本书的第十一章 文章目录《Getting Started with NLP》chap11&#xff1a;Named-entity recognition11.1 Named entity recognition: Definition…

jar转成dex文件

jar转成dex文件 dx 可以利用android studio中的dx工具。 可以看到android的tool安装位置: 在此路径下的如下目录有dx.bat,这个正是我们需要使用的工具。 D:\sdk\build-tools\30.0.3将dx.bat添加到环境变量 基本指令 > dx --dex --output 输出路径 待转化的jar包C

高性能网络模式:Reactor 和 Proactor

文章目录演进多 Reactor 多进程 / 线程Proactor总结演进 如果要让服务器服务多个客户端&#xff0c;那么最直接的方式就是为每一条连接创建线程。其实创建进程也是可以的&#xff0c;原理是一样的&#xff0c;进程和线程的区别在于线程比较轻量级些&#xff0c;线程的创建和线…

【Dash搭建可视化网站】项目12:全球恐怖主义数据大屏制作步骤详解

全球恐怖主义数据大屏制作步骤详解1 项目效果图2 项目架构3 文件介绍和功能完善3.1 assets文件夹介绍3.2 app.py和index.py文件完善3.3 header.py文件完善3.4 filteritem.py文件完善3.5 api.py文件和api.ipynb文件完善3.6 staclbarline.py文件完善3.7 piechart.py文件完善3.8 m…

IO多路复用之select、poll、epoll之间的区别总结

一、IO多路复用基本概念 select、poll、epoll都是IO多路复用的机制。IO多路复用就是通过一种机制&#xff0c;让一个进程/线程可以监视多个描述符&#xff0c;一旦某个描述符就绪&#xff08;一般是读写就绪&#xff09;&#xff0c;能够通知应用程序进行相应的读写操作。 I/…

并网逆变器学习笔记5---三电平DPWM

参考文献&#xff1a;《中压三电平全功率风电变流器关键技术研究---任康乐》 1、调制策略分析 DPWM由于其在任意时刻均有一相钳位在某个电平&#xff0c;使得该相的功率器件不发生开关动作&#xff0c;因而可以大大降低开关损耗&#xff08;平均降低1/3&#xff09;&#xff…

Java多线程案例——定时器

一&#xff0c;定时器1.定时器的概念定时器是Java开发中一个重要的组件&#xff08;功能类似于闹钟&#xff09;&#xff0c;可以指定一个任务在多长时间后执行&#xff08;尤其在网络编程的时候&#xff0c;如果网络卡顿很长时间没有响应用户的需求&#xff0c;此时可以使用定…

分享|UWB使用频段大幅收窄,新标准对于行业发展是好是坏?

近日&#xff0c;工信部无线电管理局发布了《超宽带&#xff08;UWB&#xff09;设备无线电管理规定&#xff08;征求意见稿&#xff09;》&#xff08;以下简称“新版《规定》”&#xff09;。 根据新版《规定》&#xff0c;未来国内UWB技术的使用频段为&#xff1a;7235-875…

seo的基本知识(概述网站内部优化和外部优化)

了解网站外部优化的4大重点 网站优化的时候都会重视网站的外部优化&#xff0c;所以网站外部优化的4大重点&#xff01;今天就来和大家说一说&#xff01; 1.高质量的内容和外链 未来的SEO道路高质量的有价值的内容是非常重要的&#xff0c;还有就是高质量的外链也是重要之…

北大硕士LeetCode算法专题课-查找相关问题

黑马算法面试专题 北大硕士LeetCode算法专题课-字符串相关问题 北大硕士LeetCode算法专题课-数组相关问题_​​​​​​ 北大硕士LeetCode算法专题课-基础算法查找_ 北大硕士LeetCode算法专题课-基础算法之排序_客 北大硕士LeetCode算法专题课---算法复杂度介绍_…

Neo4j框架学习之一安装和使用

文章目录1、何为Neo4j2、安装和使用2.1 安装2.2 基础概念1、何为Neo4j ​ Neo4j是一个高性能的NOSQL图形数据库&#xff0c;是一个嵌入式的、基于磁盘的&#xff0c;数据结果为网格(图)、具备完全的事务特性的Java持久化引擎。 数据结构 ​ 在一个图中包含两种基本的数据类型…

从浏览器里输入URL构建你的前端知识体系

嗨&#xff01;我是团子&#xff0c;好久不见~ 记得22年寒假复习八股的时候&#xff0c;一直在苦恼怎样才能把八股的内容真正的转换为自己的知识。毕竟光靠死记硬背每个知识点&#xff0c;是不能在面试中给面试官留下不错的印象的。后面在整理《浏览器里输入URL后发生了什么》…

Stellarium 1.2 正式发布

导读Stellarium 1.2 已发布。Stellarium 是一款免费开源 GPL&#xff08;自由软件基金会 GNU 通用公共许可证&#xff09;软件&#xff0c;它使用 OpenGL 图形接口对星空进行实时渲染。 软件可以模拟肉眼、双筒望远镜和小型天文等观察天空&#xff0c;根据观测者所处时间和位置…

项目管理:项目经理如何创建项目日程计划表

当项目经理接手项目后&#xff0c;要做好项目的日程安排&#xff0c;这是决定项目是否成功完成的最重要任务之一。 项目经理都希望项目按照制定好的进度计划完工&#xff0c;但在实际的情况中&#xff0c;总会有那么一两个项目会出现进度延迟的情况&#xff0c;管理者可以使用…

忆享科技戟星安全实验室|OSS的STS模式授权案例

戟星安全实验室忆享科技旗下高端的网络安全攻防服务团队.安服内容包括渗透测试、代码审计、应急响应、漏洞研究、威胁情报、安全运维、攻防演练等。本文约957字&#xff0c;阅读约需3分钟。前言《漏洞挖掘系列》将作为一个期刊持续更新&#xff0c;我们会将项目中所遇到的觉得有…

图像编辑Photoshop 2023中文新

Photoshop2023从照片编辑和合成到数字绘画、动画和图形设计-只要能想到&#xff0c;就能在Photoshop中创作出来。相信大家都有在用之前的版本&#xff0c;这款软件功能丰富&#xff0c;实用性很强&#xff0c;有着大量的功能用户都可以用上&#xff0c;不管是美化还是滤镜&…

基于冲突搜索(CBS)的多智能体路径寻优(MAPF)

1 背景 1.1 问题描述 多智能体路径寻优( Multi-Agent Path Finding&#xff0c;MAPF )问题由一个无向无权图G ( V &#xff0c;E )和一组k个智能体组成&#xff0c;其中智能体有起始点和目标点。时间被离散化为时间步。在连续的时间步之间&#xff0c;每个智能体既可以移动到…

Kafka生产者——消息发送流程,同步、异步发送API

生产者消息发送流程 发送原理 Kafka的Producer发送消息采用的是异步发送的方式。 在消息发送的过程中&#xff0c;涉及到了两个线程:main线程和Sender线程&#xff0c;以及一个线程共享变量:RecordAccumulator。 ①main线程中创建了一个双端队列RecordAccumulator&#xff0c…

Spring Boot 创建和使用

Spring Boot 创建和使用一、什么是 Spring Boot二、Spring Boot 优点三、Spring Boot 项目创建3.1 使用 Idea 创建验证3.2 网页版创建四、项目目录介绍五、约定大于配置 (重要)5.1 启动类5.2 自定义类在目录中的位置一、什么是 Spring Boot Spring 的诞⽣是为了简化 Java 程序…

《架构300讲》学习笔记(51-100)

前言 内容来自B站IT老齐架构300讲内容。 053动静分离 静态数据&#xff1a;无个性化的数据&#xff0c;静态文件&#xff0c;低频变动的数据。 动态数据&#xff1a;个性化推荐&#xff0c;高频写。 有效的区分页面中的动静数据是优化的关键前提。 页面伪静态化技术&#x…