ffmpeg 的帮助系统

-----------------------------------------------
author: hjjdebug
date:   2023年 07月 31日 星期一 14:32:15 CST
ffmpeg  的帮助系统
目的: 搞清楚它都打印了什么? 它是怎样实现的.
-----------------------------------------------
$ffprobe -h  1996行输出
$ffmpeg -h    111行输出
$ffplay -h    8492行输出

########################################
甲: 先分析ffprobe -h
########################################
$ffprobe -h  1996行输出
剥皮之后来到
void show_help_default(const char *opt, const char *arg)
它包含3个部分:
show_help_options(options, "Main options:", 0, 0, 0); // 把options 选项的help 信息全部打印出来,68行输出,实现是枚举这个options表
show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM); // 把av_format_context_class类及其子类解码参数的帮助信息打印, 长到1270
show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM); // 把av_codec_context_class类及其子类解码参数的帮助信息打印, 长到1994

show_help_options() 函数后面三参数是3个flag, 包含flag,抛弃flag,alt_flag, 可看后面描述, 为0是不考虑的意思.
目前可简单理解为把 ffprobe 的主选项 的帮助信息(或说描述信息)都打印出来
------------------------------------------------------------
看第2部分, avformat 类及其子类的帮助
show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM); // 把av_format_context_class类族解码参数的帮助信息打印, 长到1270
------------------------------------------------------------
void show_help_children(const AVClass *class, int flags, int level) // 这是一个递归调用函数, level 是我加上的参数,为了搞清楚它的层次调用参数
{
    if (class->option) { //它传来的AVClass 是名叫AVFormatContext的类. 根据该对象的options 表位置,
        printf("----level %d ----\n",level);
        av_opt_show2(&class, NULL, flags, 0);  // 先处理自己, 依据flags, 漂亮的组织打印内容.
        printf("\n");
    }

    void *iter = NULL;
    const AVClass *child;
    while (child = av_opt_child_class_iterate(class, &iter)) //然后枚举它的子类,
    {
        show_help_children(child, flags,++level); //递归调用该函数.
        level--;
    }
}
先处理自己,再枚举递归叫先序遍历. 反之叫后序遍历.
处理很简单(代码简单,递归),但关系很复杂,这么多类(几百个类)它们的关系是什么?
我看了一下,大部分都是一级(儿子), 少部分有层级关系,最大3级.
例如:

----level 1 ----
AVIOContext AVOptions:
  -protocol_whitelist <string>     .D......... List of protocols that are allowed to be used

----level 2 ----
URLContext AVOptions:
  -protocol_whitelist <string>     .D......... List of protocols that are allowed to be used
  -protocol_blacklist <string>     .D......... List of protocols that are not allowed to be used
  -rw_timeout        <int64>      ED......... Timeout for IO operations (in microseconds) (from 0 to I64_MAX) (default 0)

----level 3 ----
Async AVOptions:

----level 3 ----
cache AVOptions:
  -read_ahead_limit  <int>        .D......... Amount in bytes that may be read ahead when seeking isn't supported, -1 for unlimited (from -1 to INT_MAX) (default 65536)

----level 3 ----
crypto AVOptions:
  -key               <binary>     ED......... AES encryption/decryption key
  -iv                <binary>     ED......... AES encryption/decryption initialization vector
  -decryption_key    <binary>     .D......... AES decryption key
  -decryption_iv     <binary>     .D......... AES decryption initialization vector

----level 3 ----
ffrtmphttp AVOptions:
  -ffrtmphttp_tls    <boolean>    .D......... Use a HTTPS tunneling connection (RTMPTS). (default false)

----level 3 ----
file AVOptions:
  -follow            <int>        .D......... Follow a file as it is being written (from 0 to 1) (default 0)
  -seekable          <int>        ED......... Sets if the file is seekable (from -1 to 0) (default -1)

----level 3 ----
ftp AVOptions:
  -timeout           <int>        ED......... set timeout of socket I/O operations (from -1 to INT_MAX) (default -1)
  -ftp-anonymous-password <string>     ED......... password for anonymous login. E-mail address should be used.
  -ftp-user          <string>     ED......... user for FTP login. Overridden by whatever is in the URL.
  -ftp-password      <string>     ED......... password for FTP login. Overridden by whatever is in the URL.

----level 3 ----
http AVOptions:
  -seekable          <boolean>    .D......... control seekability of connection (default auto)
  -http_proxy        <string>     ED......... set HTTP proxy to tunnel through
  -headers           <string>     ED......... set custom HTTP headers, can override built in default headers
  -content_type      <string>     ED......... set a specific content type for the POST messages

我终于明白为什么要标注代码了,
因为上层描述,不足以描述清楚其细节.
代码之精妙,需要一步步标注其代码才能说清其中的关系,
并且还要用更多语言描述其精妙之处,包括参数,返回值,甚至直达bit

下面把代码copy 过来标注:

//分析av_opt_child_class_iterate 函数, 这类似于c++代理模式, 你让我干什么,我就让代理干什么.
//而这里的代理就是调用者自己, 你让我干什么,传给我函数,我让函数干什么, 这也就c的回调函数
const AVClass *av_opt_child_class_iterate(const AVClass *class, void **iter)
{
    if (class->child_class_iterate) // 如果传来的类参数包含枚举函数,
        return class->child_class_iterate(iter); // 就调用这个类参数包含的枚举函数并返回
    return NULL;
}

每一个层次对孩子们的枚举方式不同,我们看看AVFormatContext 的枚举方式, 这是AVFormatContext 的枚举回调
enum {
    CHILD_CLASS_ITER_AVIO = 0,
    CHILD_CLASS_ITER_MUX,
    CHILD_CLASS_ITER_DEMUX,
    CHILD_CLASS_ITER_DONE,

};
#define ITER_STATE_SHIFT 16
static const AVClass *format_child_class_iterate(void **iter)
{
    // we use the low 16 bits of iter as the value to be passed to
    // av_(de)muxer_iterate()
    // 用val 作为muxer,demuxer 枚举下一个的索引
    void *val = (void*)(((uintptr_t)*iter) & ((1 << ITER_STATE_SHIFT) - 1)); //就是说val不会超过16位,它实际上是表格的索引!!
    //用state (状态), 描述它目前处于那个层次
    unsigned int state = ((uintptr_t)*iter) >> ITER_STATE_SHIFT;
    const AVClass *ret = NULL;

    if (state == CHILD_CLASS_ITER_AVIO) {
        ret = &ff_avio_class;  // avio 只会进来一次, 但avio 还会有自己的孩子们
        state++;
        goto finish;
    }

    if (state == CHILD_CLASS_ITER_MUX) {
        const AVOutputFormat *ofmt;

        while ((ofmt = av_muxer_iterate(&val))) { // muxer 都是format 的儿子, val为下一个的索引
            ret = ofmt->priv_class;  //找到包含类的地址,返回
            if (ret)
                goto finish;
        }

        val = NULL;
        state++;
    }

    if (state == CHILD_CLASS_ITER_DEMUX) {
        const AVInputFormat *ifmt;

        while ((ifmt = av_demuxer_iterate(&val))) { // muxer 都是format 的儿子, val为下一个的索引
            ret = ifmt->priv_class; //找到包含类的地址,返回
            if (ret)
                goto finish;
        }
        val = NULL;
        state++;
    }

finish:
    // make sure none av_(de)muxer_iterate does not set the high bits of val
    av_assert0(!((uintptr_t)val >> ITER_STATE_SHIFT));
    *iter = (void*)((uintptr_t)val | (state << ITER_STATE_SHIFT));
    return ret;
}

好了,对av_format_context_class 的枚举搞清楚了, 以后想在其下加一个context 也可以操作了.!
------------------------------------------------------------
看第3部分. avcodec 类的帮助
show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM); // 把av_codec_context_class类族解码参数的帮助信息打印, 长到1994
------------------------------------------------------------
有了第2部分的铺垫,第3部分就容易了,因为它们调用同一个函数,只是第一个参数class 指针不同而已.
void show_help_children(const AVClass *class, int flags, int level)
{
    if (class->option) {
        printf("----level %d ----\n",level);
        av_opt_show2(&class, NULL, flags, 0); //传来的类实例是AVCodecContext, 先打印自己,这是0级,
        printf("\n");
    }

    void *iter = NULL; // 它如果改为 int index=0, 读者会更容易理解, 因为*iter是按0,1,2,3...来改变的,并不是指针.
    const AVClass *child;
    while (child = av_opt_child_class_iterate(class, &iter)) //再枚举孩子们打印
    {
        show_help_children(child, flags,++level);
        level--;
    }
}

//再分析一次av_opt_child_class_iterate 函数, 这类似于c++代理模式, 你让我干什么,我就让代理干什么.
//而这里的代理就是调用者自己, 你让我干什么,传给我函数,我让函数干什么, 这也就c的回调函数
const AVClass *av_opt_child_class_iterate(const AVClass *class, void **iter)
{
    if (class->child_class_iterate) // 如果传来的类参数包含枚举函数,
        return class->child_class_iterate(iter); // 就调用这个类参数包含的枚举函数并返回
    return NULL;
}
我们看看这个回调函数,
static const AVClass *codec_child_class_iterate(void **iter) //这个传来的地址,包含着索引信息
{
    const AVCodec *c;
    /* find next codec with priv options */
    while (c = av_codec_iterate(iter)) //它就是很简单的表格(数组)枚举了.
        if (c->priv_class)
            return c->priv_class;
    return NULL;
}

//说它简单,功能确实简单,但也有可圈点之处.
const AVCodec *av_codec_iterate(void **opaque)
{
    uintptr_t i = (uintptr_t)*opaque; //怎样拿到索引号,靠参数
    const AVCodec *c = codec_list[i];
    if (c)
        *opaque = (void*)(i + 1); //把下一个索引号,还保留到参数中,参数是个地址. 地址是调用者的一个局部变量地址

    return c;
}

########################################
乙: 分析ffmpeg -h
########################################
ffmpeg 的分析多了一个split_commandline()函数, 它的实现不是这里分析的重点.执行结果是把argc,argv参数转移到了octx中
/* split the commandline into an internal representation */
ret = split_commandline(&octx, argc, argv, options, groups, FF_ARRAY_ELEMS(groups));
下一句完成所有打印输出工作.
 ret = parse_optgroup(NULL, &octx.global_opts); --> 关键是执行了下一句
 ret = write_option(octx, o->opt, o->key, o->val); --> 下面是根据option定义找到一个要执行的函数.

//代码有简化
int show_help(void *optctx, const char *arg)
{
    av_log_set_callback(log_callback_help);
    char *topic = arg
    char *par = strchr(topic, '=');  // -h 后面参数, =前面是topic, =后面是arg, 无参数 *topic 为0
    if (par) *par++ = 0;

    if (!*topic) {
        show_help_default(topic, par);  // -h 无参数走的是这路, *topic=0
    } else if (!strcmp(topic, "decoder")) { //例 -h decoder=h264, =后必需要跟名字, 名字可以用 -decoders查询
        show_help_codec(par, 0);
    } else if (!strcmp(topic, "encoder")) {  //例 -h encoder=h264, =后必需要跟名字,名字可以用 -encoders查询
        show_help_codec(par, 1);
    } else if (!strcmp(topic, "demuxer")) {//例 -h demuxer=h264, =后必需要跟名字,名字可以用 -demuxers查询
        show_help_demuxer(par);
    } else if (!strcmp(topic, "muxer")) {//例 -h muxer=h264, =后必需要跟名字,名字可以用 -muxers查询
        show_help_muxer(par);
    } else if (!strcmp(topic, "protocol")) {//例 -h protocol=file =后必需要跟名字,名字可以用 -protocols查询
        show_help_protocol(par);
#if CONFIG_AVFILTER
    } else if (!strcmp(topic, "filter")) { //例 -h filter=overlay =后必需要跟名字,名字可以用 -filters查询
        show_help_filter(par);
#endif
    } else if (!strcmp(topic, "bsf")) { //例 -h bsf=h264_mp4toannexb =后必需要跟名字,名字可以用 -bsfs查询
        show_help_bsf(par);
    } else {
        show_help_default(topic, par); //默认走这里
    }

    av_freep(&topic);
    return 0;
}


void show_help_default(const char *opt, const char *arg)
{
    int show_advanced = 0, show_avoptions = 0;
    if (opt && *opt) {
        if (!strcmp(opt, "long"))
            show_advanced = 1;
        else if (!strcmp(opt, "full"))
            show_advanced = show_avoptions = 1;
        else
            av_log(NULL, AV_LOG_ERROR, "Unknown help option '%s'.\n", opt);
    }

    show_usage(); // 打印一行台头

    printf("Getting help:\n"      //打印如何获取帮助. -h, -h long, -h full, -h type=name
           "    -h      -- print basic options\n"
           "    -h long -- print more options\n"
           "    -h full -- print all options (including all format and codec specific options, very long)\n"
           "    -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf/protocol\n"
           "    See man %s for detailed description of the options.\n"
           "\n", program_name);

    //打印具体包含哪些type, type 是个类,知道了type, 还可以用 -types 查看该type下具体包含哪些种. 这样 -h type=name 就完整了.
    show_help_options(options, "Print help / information / capabilities:", OPT_EXIT, 0, 0);

    /* per-file options have at least one of those set */
    const int per_file = OPT_SPEC | OPT_OFFSET | OPT_PERFILE;
    //req_flags 为0,所有项参与,rej_flags=per_file |OPT_EXIT|OPT_EXPERT, 有这些标志的项均不显示
    //此为显示全局标志
    show_help_options(options, "Global options (affect whole program" "instead of just one file):", 0, per_file | OPT_EXIT | OPT_EXPERT, 0);
    if (show_advanced)
        show_help_options(options, "Advanced global options:", OPT_EXPERT, per_file | OPT_EXIT, 0); //显示OPT_EXPERT项,但不包含per_file|OPT_EXIT标志

    //要求有per_file标志,但过滤了一些标志
    //此为显示每个文件都具有的主选项,项fmt,codec,start time,duration, frame等
    show_help_options(options, "Per-file main options:", 0, OPT_EXPERT | OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE | OPT_EXIT, per_file);
    if (show_advanced)
        show_help_options(options, "Advanced per-file options:", OPT_EXPERT, OPT_AUDIO | OPT_VIDEO | OPT_SUBTITLE, per_file);

    //要求是OPT_VIDEO,过滤了OPT_EXPERT|OPT_AUDIO
    //此为video 选项
    show_help_options(options, "Video options:", OPT_VIDEO, OPT_EXPERT | OPT_AUDIO, 0);
    if (show_advanced)
        show_help_options(options, "Advanced Video options:", OPT_EXPERT | OPT_VIDEO, OPT_AUDIO, 0); //添一部分,但不能是OPT_AUDIO flag

    //此为audio 选项
    show_help_options(options, "Audio options:", OPT_AUDIO, OPT_EXPERT | OPT_VIDEO, 0); // 类似处理
    if (show_advanced)
        show_help_options(options, "Advanced Audio options:", OPT_EXPERT | OPT_AUDIO, OPT_VIDEO, 0);

    //此为subtitle 选项
    show_help_options(options, "Subtitle options:", OPT_SUBTITLE, 0, 0); //要求是OPT_SUBTITLE flag
    printf("\n");

    if (show_avoptions) { // 如果打开了 show_avoptions, 还会显示子类的帮助信息,这里就不分析了.
        int flags = AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM;
        show_help_children(avcodec_get_class(), flags,0);
        show_help_children(avformat_get_class(), flags,0);
        show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM,0);
        show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM,0);
    }
}

关键是show_help_options() 函数
不懂的东西都在代码里,怪不得要标注代码呢. 一下就明白req, rej 是如何起作用的了.
void show_help_options(const OptionDef *options, const char *msg, int req_flags, int rej_flags, int alt_flags)
{
    const OptionDef *po;
    int first;

    first = 1;
    for (po = options; po->name; po++) {
        char buf[128];

//option flag 必需要包含 req_flag,如果alt_flag存在,也必需包含alt_flag, 不能包含rej_flag 才会打印输出
        if (((po->flags & req_flags) != req_flags) ||
            (alt_flags && !(po->flags & alt_flags)) ||
            (po->flags & rej_flags))
            continue;

        if (first) {
            printf("%s\n", msg);
            first = 0;
        }
        av_strlcpy(buf, po->name, sizeof(buf));
        if (po->argname) {
            av_strlcat(buf, " ", sizeof(buf));
            av_strlcat(buf, po->argname, sizeof(buf)); //把选项名称,选项参数名称连接起来输出
        }
        printf("-%-17s  %s\n", buf, po->help);
    }
    printf("\n");
}
########################################
丙: 分析ffplay -h
########################################
show_help_default(topic, par);
但这次连接的是ffplay.c 下的, 代码非常简洁,但打印的内容很多,8千多行输出. 所以你要会看主要的.
void show_help_default(const char *opt, const char *arg)
{
    av_log_set_callback(log_callback_help);
    show_usage(); //一行台头
    show_help_options(options, "Main options:", 0, OPT_EXPERT, 0); // ffplay主选项输出
    show_help_options(options, "Advanced options:", OPT_EXPERT, 0, 0); // ffplay高级选项输出
    printf("\n");
    show_help_children(avcodec_get_class(), AV_OPT_FLAG_DECODING_PARAM,0);  //AVCodecContext 类族的帮助信息
    show_help_children(avformat_get_class(), AV_OPT_FLAG_DECODING_PARAM,0); //AVFormatContext 类族的帮助信息
#if !CONFIG_AVFILTER
    show_help_children(sws_get_class(), AV_OPT_FLAG_ENCODING_PARAM,0);
#else
    show_help_children(avfilter_get_class(), AV_OPT_FLAG_FILTERING_PARAM,0); //AVFilterContext 类族的帮助信息
#endif
    printf("\nWhile playing:\n"                                //这是ffplay 的操控按键, 很有用!
           "q, ESC              quit\n"
           "f                   toggle full screen\n"
           "p, SPC              pause\n"
           "m                   toggle mute\n"
           "9, 0                decrease and increase volume respectively\n"
           "/, *                decrease and increase volume respectively\n"
           "a                   cycle audio channel in the current program\n"
           "v                   cycle video channel\n"
           "t                   cycle subtitle channel in the current program\n"
           "c                   cycle program\n"
           "w                   cycle video filters or show modes\n"
           "s                   activate frame-step mode\n"
           "left/right          seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n"
           "down/up             seek backward/forward 1 minute\n"
           "page down/page up   seek backward/forward 10 minutes\n"
           "right mouse click   seek to percentage in file corresponding to fraction of width\n"
           "left double-click   toggle full screen\n"
           );
}
在 /home/hjj/FFmpeg-n4.4/fftools/cmdutils.c 下调用 show_help_default() 函数, 根据执行文件的不同,它可能会连接到
ffprobe.c 或 ffmpeg.c 或 ffplay.c , 而这三个执行文件中各有各的实现. 这属于不同的执行文件,没什么好说的.
它们各自调用的函数,主要还是show_help_options(), show_help_children() 前面已经详细分析过了,如此帮助系统分析完毕!

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

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

相关文章

Java如何实现将类文件打包为jar包

目录 将类文件打包为jar包 1.写类文件2.编译3.测试4.打jar包jar包应该怎么打&#xff1f; 1.首先确保你的项目2.选中你的项目,点右键3.选择runnable jar file4.如下图,直接看图5.然后点finish 将类文件打包为jar包 为实际项目写了一个工具类&#xff0c;但是每次使用时都需要…

xcode中如何显示文件后缀

xcode14.3 用不惯mac电脑真恶心&#xff0c;改个显示文件后缀找半天 1、首先双击打开xcode软件 2、此时&#xff0c;电脑左上角出现xcode字样(左上角如果看不到xcode字样&#xff0c;再次点击xcode软件弹出来就有了)&#xff0c;鼠标右键它&#xff0c;点击setting或者Prefere…

阿里云SLB负载均衡ALB、CLB和NLB有什么区别?

阿里云负载均衡SLB分为传统型负载均衡CLB&#xff08;原SLB&#xff09;、应用型负载均衡ALB和网络型负载均衡NLB&#xff0c;三者有什么区别&#xff1f;CLB是之前的传统的SLB&#xff0c;基于物理机架构的4层负载均衡&#xff1b;ALB是应用型负载均衡&#xff0c;7层负载均衡…

安卓音视频多对多级联转发渲染

最近利用自己以前学习和用到的音视频知识和工程技能做了一个android的sdk,实现了本地流媒体ipc rtsp 拉流以及自带mip usb等camera audio节点产生的流媒体通过webrtc sfu的方式进行多对多级联发布共享,网状结构&#xff0c;p2p组网&#xff0c;支持实时渲染以及转推rtmp&#x…

我的第一个前端(VS code ,Node , lite-server简易服务器,npm 运行)

第一种方式&#xff1a;使用Visual Studio Code创建并运行 第一个前端项目的步骤&#xff0c;如下&#xff1a; 1. 下载和安装Visual Studio Code&#xff1a; 访问Visual Studio Code官方网站&#xff08;Visual Studio Code - Code Editing. Redefined&#xff09;并根据你…

Java类的加载过程是什么?

本文重点 本文将学习类的加载过程,java命令将class文件放到类加载器中,那么之后经历了什么?本文将对其进行学习。 类加载方式? 两种加载方式:隐式加载(静态加载)和显式加载(动态加载) 隐式加载指的是在程序使用new等方式创建对象的时候,会隐式地调用类的加载器把…

【Docker】Docker的优势、与虚拟机技术的区别、三个重要概念和架构及工作原理详细讲解

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 作者简介&#xff1a; 辭七七&#xf…

GDAL C++ API 学习之路 OGRGeometry 环类 OGRLinearRing

OGRLinearRing class <ogrsf_frmts.h> OGRLinearRing 是 OGR 库中的一个类&#xff0c;它是一个线性环&#xff08;Linear Ring&#xff09;的几何对象&#xff0c;用于表示封闭的线性路径。线性环是由一系列连续的线段组成&#xff0c;首尾相连形成闭合的环。线…

驶向专业:嵌入式开发在自动驾驶中的学习之道

导语: 自动驾驶技术在汽车行业中的快速发展为嵌入式开发领域带来了巨大的机遇。作为自动驾驶的核心组成部分&#xff0c;嵌入式开发在驱动汽车的智能化和自主性方面发挥着至关重要的作用。本文将探讨嵌入式开发的学习方向、途径以及未来在自动驾驶领域中的展望。 一、学习方向:…

Java 解析Excel单元格的富文本

1. 总体介绍 该方法是解析 xlsx 单元格中的富文本&#xff0c;注意不是 xls&#xff0c;xls 的 api 不一样&#xff0c;试了很久没成功。只实现了解析 斜体字、上下标&#xff0c;其它的实现方式应该类似。 2. 具体实现 2.1 代码 package util;import java.io.FileInputStr…

人工智能安全-3-噪声数据处理

0 提纲 噪声相关概述噪声处理的理论与方法基于数据清洗的噪声过滤主动式过滤噪声鲁棒模型1 噪声相关概述 噪声类型: 属性噪声:样本中某个属性的值存在噪声标签噪声:样本归属类别关于噪声分布的假设:均匀分布、高斯分布、泊松分布等。 标签噪声的产生原因: (1)特定类别…

[SQL挖掘机] - 窗口函数 - dense_rank

介绍: dense_rank() 是一种常用的窗口函数&#xff0c;它为结果集中的每一行分配一个密集排名&#xff08;dense rank&#xff09;。这个密集排名基于指定的排序顺序&#xff0c;并且在遇到相同的值时&#xff0c;不会跳过排名。 用法: dense_rank() 函数的语法如下&#xf…

ERROR: transport error 202: gethostbyname: unknown host报错解决方案

Java 9 syntax for remote debugger: -agentlib:jdwptransportdt_socket,servery,suspendn,address*:5005Java 8 不适用 *:port&#xff0c;应该使用: -agentlib:jdwptransportdt_socket,servery,suspendn,address5005参考 https://stackoverflow.com/questions/50344957/ja…

C++ 文件流操作详解

1. C I/O流 本文章有很多内容参考并借鉴了《C primer plus》 这本经典。这里先说明一下。 1. C I/O流 1.1. 数据流1.2. 控制台流1.3. 文件流 1.3.1. 什么是文件流&#xff1f;1.3.2. 缓冲区1.3.3. 文件流和控制流的关系1.3.4. 文件处理1.3.5. 简单的文件I/O1.3.6. 流状态检查和…

Day11-作业(SpringBootWeb案例)

作业1&#xff1a;完成课上所讲解的部门管理、员工管理的所有功能。[必须] 部门管理&#xff1a; 查询部门 删除部门 新增部门 修改部门 员工管理&#xff1a; 条件分页查询 批量删除员工 新增员工 修改员工 文件上传 作业2&#xff1a;整理 文件上传、配置文件 [必…

MATLAB RANSAC圆柱体点云拟合 (28)

MATLAB RANSAC圆柱体点云拟合 (28) 一、算法介绍二、函数介绍三、算法实现四、效果展示一、算法介绍 RANSAC拟合方法,从原始点云中拟合具有特定形状的点云,这里对原始点云中大致呈圆柱的点云进行分割,圆柱的半径,以及朝向都是比较重要的定义圆柱的参数。下面是具体使用的…

Mysql-学习笔记

文章目录 1. 数据库1.1 Mysql安装及常用代码1.2 SQL介绍1.3 SQL分类1. DDL-操作数据库&#xff0c;表2. DML-对表中的数据进行增删改3. DQL-对表中的数据进行查询条件查询模糊查询排序查询分组查询分页查询 4. DCL-对数据库进行权限控制外键约束表关系-多对多多表查询事务 1. 数…

ETHERNET/IP转RS485/RS232网关什么是EtherNet/IP?

网络数据传输遇到的协议不同、数据互通麻烦等问题&#xff0c;一直困扰着大家。然而&#xff0c;现在有一种神器——捷米JM-EIP-RS485/232&#xff0c;它将ETHERNET/IP网络和RS485/RS232总线连接在一起&#xff0c;让数据传输更加便捷高效 那么&#xff0c;它是如何实现这一功能…

建木使用进阶-创建密钥管理

阿丹&#xff1a; 第一次我们进入建木&#xff0c;第一件事情就是配置我们相关的密钥。 解读&#xff1a; 在建木中我们可以进行创建密钥来对我们服务器等密码进行方便的管理。 注意&#xff1a; 登录的时候账号为&#xff1a;admin 密码为&#xff1a;123456 这是初始…

Kubernetes(K8s)从入门到精通系列之四:K8s的基本概念和术语之集群类

Kubernetes K8s从入门到精通系列之四:K8s的基本概念和术语之集群类 一、Master二、Node三、命名空间集群表示一个由Master和Node组成的K8s集群。 一、Master Master指的是集群的控制节点。在每个K8s集群都需要有一个或一组被称为Master的节点,来负责整个集群的管理和控制。M…